The Wayback Machine - https://web.archive.org/web/20210729183048/https://github.com/microsoft/TypeScript/issues/41893
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

type ${number} cannot be used to index numeric index signature #41893

Closed
ajafff opened this issue Dec 9, 2020 · 8 comments
Closed

type ${number} cannot be used to index numeric index signature #41893

ajafff opened this issue Dec 9, 2020 · 8 comments

Comments

@ajafff
Copy link
Contributor

@ajafff ajafff commented Dec 9, 2020

TypeScript Version: 4.2.0-dev.20201209

Search Terms:

Expected behavior:

type ${number} can be used to index numeric index signature

Actual behavior:

Error: Element implicitly has an 'any' type because index expression is not of type 'number'.

Related Issues:

Code

declare let t: `${number}`;

declare let obj: {
    [key: number]: number;
}

const v = obj[t];

Playground Link: Provided

@weswigham
Copy link
Member

@weswigham weswigham commented Dec 9, 2020

...but should it? ${number} admits strings like "-1.0e1", which a number index signature does not (since such a string, while parseable as a number, does not fill a numeric slot on the object!).

@ajafff
Copy link
Contributor Author

@ajafff ajafff commented Dec 9, 2020

I recall that I read something about the requirement for ${number} in template literal types to round-trip (parsing as number and stringifying gives the same string).
But testing with const a: `${number}` = '1.0'; shows that this is not the case.

@RyanCavanaugh
Copy link
Member

@RyanCavanaugh RyanCavanaugh commented Dec 10, 2020

The round-tripping is not a requirement, so @weswigham 's analysis is correct

@ajafff ajafff closed this Dec 11, 2020
@jcalz
Copy link
Contributor

@jcalz jcalz commented Jul 24, 2021

@RyanCavanaugh said

The round-tripping is not a requirement

Hmm, seems like it should be, right? I'd expect `${number}` to correspond exactly to those values `${n}` where n is of type number. Of course, we already look the other way with things like NaN and Infinity, so maybe not. In any case, has the round-trip functionality actually been discussed and declined? Or did it merely not get implemented yet? Is there an existing issue to track it? If not, should I open one?

@RyanCavanaugh
Copy link
Member

@RyanCavanaugh RyanCavanaugh commented Jul 26, 2021

Hmm, seems like it should be, right? I'd expect ${number} to correspond exactly to those values ${n} where n is of type number

This would imply that "1.0" wouldn't be a valid ${number}, which I think would be extraordinarily surprising.

@jcalz
Copy link
Contributor

@jcalz jcalz commented Jul 26, 2021

Wow, my intuition is exactly the opposite; could you articulate why it would be surprising? You must be looking at the class of valid string-to-number inputs, while I'm looking at the class of valid number-to-string outputs, and both of us are thinking "yep, that's the natural meaning of `${number}`". What's the intuition that drives your view?

Mine is that template literal types should correspond to (untagged) template literal values. Such template literals can consume numbers and produce strings, but they don't consume strings to produce numbers. If "1.0" and "0xfacade" are valid `${number}` values, then the type `${number}` doesn't have much, if anything, to do with template literals at all. It's more like "the strings s where Number(s) or +s is not NaN". It gets worse for a type like `foo${number}bar`: you need to say something like "those strings `foo${s}bar` where s is a string where +s is not NaN", instead of the much more straightforward "those strings `foo${n}bar` where n is a number".

Furthermore, the set of valid number-to-string outputs has a use case we already care about in TypeScript: "numeric" object indices. And while the set of string-to-number inputs might be useful, we don't currently have a string-to-number type function (as in #26382) to use with it. So I'd be interested in seeing use cases where the prohibition of "1.0" and "0xfacade" would break things.

@RyanCavanaugh
Copy link
Member

@RyanCavanaugh RyanCavanaugh commented Jul 29, 2021

I ran a poll and most people seem to have the reverse interpretation https://twitter.com/SeaRyanC/status/1420059847156928512

@jcalz
Copy link
Contributor

@jcalz jcalz commented Jul 29, 2021

Oh, well, 78.6% of respondents are wrong! Kidding, kind of. I guess `${number}s` don't lie! But I wonder if you'd have gotten different results if you had asked about

let s4: `${number}%` = "0xfacade%"; // okay or error
(arr: string[], idx: `${number}`) => arr[idx]; // okay or error
let s5: `This sentence is ${boolean}` = "This sentence is 0"; // okay or error
let s6: `${100.0}%` = "100.0%"; // okay or error

instead. In any case, this really makes me wish we had a different notation for strings-that-are-coercible-to-finite-numbers (maybe a new intrinsic type like type numericLiteralString = intrinsic) because the current notation is hard to square with how it's being used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants