Repository navigation
Bug: (Any) string is assignable to numeric templated literal type #40538
Description
Activity
- changed the title
[-]Bug: (Any string) is assignable to templated literal type[/-][+]Bug: (Any string) is assignable to numeric templated literal type[/+]on Sep 14, 2020 - changed the title
[-]Bug: (Any string) is assignable to numeric templated literal type[/-][+]Bug: (Any) string is assignable to numeric templated literal type[/+]on Sep 14, 2020 - addedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bugNeeds InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.and removedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
on Sep 14, 2020 RyanCavanaugh commented
on Sep 14, 2020 MemberMore actionsAnders Hejlsberg (@ahejlsberg) how is this supposed to work?
Isn’t this intended behaviour?
Any one of the types any, string, number, boolean, or bigint in a placeholder causes the template literal to resolve to type string.
If it works as intended, how can I define a string-type that contains only numbers and has a certain suffix?
Example: ‘42px’
This is working as intended, but could be a suggestion. The instantiation
Foo<number>resolves to`${number}`which then resolves tostring(we do the same when a placeholder is instantiated tostringorbigint).We could consider keeping templates such as
`${number}`or`start-${string}-end`around and introduce assignability rules similar to what we do in type inference. I had some of that in place at one time, but was concerned it leads us down the slippery slope towards full on regular expression types. But we're sort of there already because of type inference, so maybe.Reacted by Joe Calzaretta and Daniel RolfI wrote this for my own project, there’s certainly room for improvement though.
This is bound to be such a common application of template literals that I do think it warrants something more ergonomic and performant.
Here's how I'd write it:
type MatchDigit<D extends string> = D extends '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ? D : never; type MatchInteger<S extends string, T = S> = S extends `${MatchDigit<infer _D>}${infer R}` ? R extends '' ? T : MatchInteger<R, T> : never; type MatchDecimal<S extends string> = S extends `${'' | '+' | '-'}${MatchInteger<infer _I>}` ? S : S extends `${'' | '+' | '-'}${MatchInteger<infer _I>}.${MatchInteger<infer _F>}` ? S : never; type MatchExtent<S extends string> = S extends `${MatchDecimal<infer _>}${'px' | 'pt'}` ? S : never; declare function takeExtent<S extends string>(ex: MatchExtent<S>): void; takeExtent('100px'); takeExtent('-1px'); takeExtent('9.5pt');
Note the trick of applying the matching productions to the
infer Xplaceholders. This works as long as each production resolves to its own type argument in one of its branches (because when inferring to a conditional type we infer to each of the branches). Also note that the validation happens during type inference, not during relationship checking. That means it isn't possible to declare a typeExtentand have validation occur in assignments.Reacted by yossarianThat’s a neat trick, thanks!
Anders Hejlsberg (@ahejlsberg) thanks for the proposal, but two remarks:
-
That Foo just resolves to a string comes as a surprise.
-
Your construct above still looks to convoluted for such a common use case (“5px”, “2.5em”) and having a short straightforward way to declare such a type would be great.
EDIT: and for sure it should also work at assignment stage, so that we can define interfaces that have fields with templates types.
-
Fixed by #40598
TypeScript Version:* 4.1.0-dev.20200914
Search Terms:
Templated literal types
Code
Expected behavior:
It should fail to compile since
"bar"should not be assignable toFoo<number>.Actual behavior:
Compiles.
Playground Link:
https://www.typescriptlang.org/play?ts=4.1.0-dev.20200914#code/C4TwDgpgBAYg9nAPAFShAHsCA7AJgZymwFcBbAIwgCcA+KAXigAMASAb2QF8mBuAKADGcbPmBQAhlABcsBIhIVqdRgCJy4qip5A
Related Issues:
#40336