Skip to content

Support inferring numeric literal types from their string representations #42938

Description

@DetachHead

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

Activity

  1. RyanCavanaugh commented on Feb 24, 2021

    @RyanCavanaugh
    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
  2. ahejlsberg commented on Feb 25, 2021

    @ahejlsberg
    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.

  3. added
    SuggestionAn idea for TypeScript
    and removed
    QuestionAn issue which isn't directly actionable in code
    on Feb 25, 2021
  4. changed the title [-]infer keyword doesn't work on intersections[/-] [+]Support inferring numeric literal types from their string representations[/+] on Feb 25, 2021
  5. jcalz commented on May 10, 2021

    @jcalz
    Contributor

    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, 👍!

  6. sno2 commented on Jan 16, 2022

    @sno2
    Contributor

    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

  7. DrJume commented on Aug 18, 2022

    @DrJume

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

  8. DetachHead commented on Aug 18, 2022

    @DetachHead
    ContributorAuthor

    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions