-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
More specific inference for constrained 'infer' types in template literal types #48094
Conversation
Could a new intrinsic like type ParseInt<AString extends string, Radix extends number = 10> = intrinsic; solve that problem? The reason I ask is that a |
I'd considered that approach, however the |
Hello, thank you very much for your work. Would the following behavior be correct with this PR? type NumToBigint<T extends number> = `${T}` extends `${Is<infer $BN, bigint>}` ? $BN : never;
type asdf = NumToBigint<23>; // 23n
type asdf2 = NumToBigint<23.5>; // never
type adsf5 = NumToBigint<-2>; // -2n |
@typescript-bot pack this |
Hey @rbuckton, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running |
Yes, that is correct. |
Additionally, might be good to have some tests that check inference to constrained type parameters of functions. For example: declare function test<T extends string | number>(s: `**${T}**`): T;
const x = test('**123**'); // Should produce "123" | 123 |
This doesn't seem to work. We correctly produce inference candidates of |
Ah, I may just need to add a new inference priority to indicate an inference to a template type placeholder. |
I've added a new |
@typescript-bot perf test |
Heya @rbuckton, I've started to run the perf test suite on this PR at df23e95. You can monitor the build here. Update: The results are in! |
21c053c
to
00c4b26
Compare
@ahejlsberg can you take another look? @weswigham I put in a check that will hopefully work with #47050, or at least be a start. |
Will this also support floating point numbers? or just integers? |
Oh, so we're not far from computing a sum of two numeric literal types! type Test = Sum<1099123, 9901123>
type ToString<A extends number> = `${A}`
type Reverse<A extends string> =
A extends `${infer H}${infer T}`
? `${Reverse<T>}${H}`
: A
type HT<T> = T extends `${infer H}${infer T}` ? {H: H, T: T} : {H: '0', T: ''}
type Head<T> = T extends `${infer H}${any}` ? H : '0'
type Tail<T> = T extends `${string}${infer T}` ? T : ''
type R0 = Tail<''>
type Concat<A, B> = A extends string ? B extends string ? `${A}${B}` : never : never
type Nums = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
type Shuffle<T extends any[]> = T extends [infer H, ...infer T] ? [...T, H] : never
type MakeTable<T extends any[], S extends any[]> = T extends [any, ...infer T] ? [S, ...MakeTable<T, Shuffle<S>>] : []
type SumTable = MakeTable<Nums, Nums>
type SumD = {0: SumTable, 1: Shuffle<SumTable>}
type Index<B, A> = A extends keyof B ? B[A] : never
type SumDR<A, B, C> = Index<Index<Index<SumD, A>, B>, C>
type Carries = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
type CarryTable = MakeTable<[0, ...Nums], Carries>
type SumC = {0: CarryTable, 1: Shuffle<CarryTable>}
type Lookup<T, C, A, B> = Index<Index<Index<T, C>, Head<A>>, Head<B>>
type SumS<A extends string, B extends string, C = 0> = Concat<A, B> extends ''
? C extends 1 ? '1' : ''
: Concat<SumS<Tail<A>, Tail<B>, Lookup<SumC, C, A, B>>, Lookup<SumD, C, A, B>>
type Sum<A extends number, B extends number> = SumS<Reverse<ToString<A>>, Reverse<ToString<B>>> |
80877c2
to
9ccca98
Compare
This modifies inference in template literal types when inferring to a constrained type variable by leveraging the constraint of the type variable to infer a more specific type:
The primary motivation for this feature is converting numeric string index keys from a tuple type into their numeric literal equivalents. While you can use something like a mapping table for a subset of numbers (i.e., as many as you are willing to manually define), that can run into issues when that might then generate a too-large union. Rather than introducing a feature specific to numeric string index keys, this instead focuses on a more general purpose solution that can apply to any valid template literal type placeholder (i.e.,
string
,number
,bigint
,boolean
,null
, andundefined
).Please note that this approach cannot be used to convert an arbitrary numeric string into a
number
orbigint
literal type, as the inferred type must still satisfy the extends condition in the conditional type. This means that a string such as"0x10"
cannot be converted to anumber
, since that value would not round-trip: If you attempt to infer a number literal type from"0x10"
, the result would be16
, however when16
is substituted back into the string literal type it becomes"16"
, which is not a supertype of"0x10"
.Also note that this PR does not introduce any new mechanism for establishing a constraint for an
infer T
type. Instead, a helper type likeIs
(above) might be necessary to enforce the constraint. A syntactic mechanism to constraininfer T
would be valuable, but is out of scope for this PR.Addendum: If we decide to take #48112, the above example could be rewritten using
infer T extends ...
instead of theIs
type alias:Fixes #47141