Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support inferring numeric literal types from their string representations #42938

Closed
DetachHead opened this issue Feb 24, 2021 · 6 comments
Closed
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@DetachHead
Copy link
Contributor

Bug Report

🔎 Search Terms

infer conditional type intersection

🕗 Version & Regression Information

4.3.0-dev.20210224

Playground link with relevant code

💻 Code

type ToNumber<T extends string> = T extends `${number & infer R}`? R: never

const foo: ToNumber<'1'> = 1 //Type 'number' is not assignable to type 'never'.

🙁 Actual behavior

T doesn't extend ${number & infer R}, even though it does extend ${number & any}

🙂 Expected behavior

T should extend ${number & infer R} and (if my understanding of infer is correct) R should be 1

@RyanCavanaugh
Copy link
Member

This isn't really going to do what you want because intersection inference deliberately discards "matching" constituents. e.g.

type Disposable = { dispose(): void };

type FooDisp = { foo: string } & Disposable
declare function nondisposable<T>(arg: T & Disposable): T;
declare const fd: FooDisp
// p: { foo: string }
const p = nondisposable(fd);

I would probably write this as

type Converter<D extends number> = D extends unknown ? [`${D}`, D] : never;
type Convert = Converter<0 | 1 | 2 | 3 /* etc to some reasonable number */>;
type Match<T, U> = T extends [U, infer V] ? V : never;
type ToNumber<T extends string> = Match<Convert, T>;

const foo: ToNumber<'1'> = 1 // OK

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Feb 24, 2021
@ahejlsberg
Copy link
Member

This sounds more like a suggestion that we should support the pattern `${number & infer T}` to infer a numeric literal type from its equivalent string representation. We currently have no way of doing that, except for limited solutions like the one above.

@ahejlsberg ahejlsberg added Suggestion An idea for TypeScript and removed Question An issue which isn't directly actionable in code labels Feb 25, 2021
@ahejlsberg ahejlsberg changed the title infer keyword doesn't work on intersections Support inferring numeric literal types from their string representations Feb 25, 2021
@RyanCavanaugh RyanCavanaugh added the In Discussion Not yet reached consensus label Feb 25, 2021
@jcalz
Copy link
Contributor

jcalz commented May 10, 2021

Is this the official place to 👍 a request for

type StrToNum<S extends string> = ✨🧙‍♀️🧙‍♂️✨ 

which is the inverse of

type NumToStr<N extends number> = `${N}`;

?

If so, 👍!

@sno2
Copy link
Contributor

sno2 commented Jan 16, 2022

This isn't really going to do what you want because intersection inference deliberately discards "matching" constituents. e.g.

type Disposable = { dispose(): void };

type FooDisp = { foo: string } & Disposable
declare function nondisposable<T>(arg: T & Disposable): T;
declare const fd: FooDisp
// p: { foo: string }
const p = nondisposable(fd);

I would probably write this as

type Converter<D extends number> = D extends unknown ? [`${D}`, D] : never;
type Convert = Converter<0 | 1 | 2 | 3 /* etc to some reasonable number */>;
type Match<T, U> = T extends [U, infer V] ? V : never;
type ToNumber<T extends string> = Match<Convert, T>;

const foo: ToNumber<'1'> = 1 // OK

Hello, thank you for your work on TypeScript. Do you have an update on this opinion now with the release of the new recursion improvements? It is now possible to create N-sized addition, subtraction, ect. types that manipulate using string types. I have done this and my integer addition type works for numbers from 0 through 99999999999999999999999999999999999999999999999 and it is A(4n) + B(4n) where n is equal to the length of the number as a string so there is still room for improvements. It would also be fairly trivial to create a floating point addition type as well using the integral addition type. The largest pitfall, however, is that you cannot convert the string number type that is the result of your operation back into a number type. Of course, you can go with the array accumulator approach where you keep shoving items into an array and check if the length as a string is equal to the number as a string but that is highly inefficient and doesn't include the complexity required for supporting floating point numbers which would definitely only work for a small subset of numbers before having a type overflow. Thanks

@DrJume
Copy link

DrJume commented Aug 18, 2022

Can this issue be closed, as the desired feature was introduced in #48094?

@DetachHead
Copy link
Contributor Author

yes it can. for the record here's how to create the ToNumber type from my OP:

type ToNumber<T extends string> = T extends `${infer Result extends number}`? Result: never

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

6 participants