microsoft / microsoft/TypeScript
Template Literal Types derived from the type keys cannot be used as Indexed Access Types in generic contexts
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
🔎 Search Terms
template literal, indexed access, keyof, key of
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about indexed access.
⏯ Playground Link
💻 Code
// Types with numeric keys.
type A = [1];
type B = 1[];
type C = { [key: number]: 1 };
type D = { 0: 1 };
// Allowed indexed access types.
type Allowed = [A[0], A['0'], A[number], A[`${number}`], B[0], B['0'], B[number], B[`${number}`], C[0], C['0'], C[number], C[`${number}`], D[0], D['0']];
// Disallowed indexed access types.
type Disallowed = [A[string], B[string], C[string], D[string], D[number], D[`${number}`]];
type NotAnIssue<T extends object> = T[`${keyof T}`];
type Issue<T extends object> = T[`${keyof T & (string | number | bigint | boolean | null | undefined)}`];
type CompactIssue<T extends object> = T[`${Exclude<keyof T, symbol>}`];
🙁 Actual behavior
The template type literal generated from keyof T cannot be used as an indexed access type for T.
🙂 Expected behavior
The template type literal generated from keyof T or its restriction can be used as an indexed access type for T, since it is restricted to be a stringified version of the key type, which should behave exactly the same as the key type in this context.
Additional information about the issue
All object types with numeric keys can be accessed with the string version of that key. However, the compiler does not acknowledge this fact in the case of generics with proper restrictions on the type.
Using `${keyof T}` directly is prohibited because template literal types cannot be constructed from symbol types. However, if the type is restricted to the allowed string | number | bigint | boolean | null | undefined, TypeScript is still refusing to use keyof T for indexed access.
The issue does not happen with definite (non-generic) types and the issue also does not occur if `${Exclude<keyof T, symbol>}` is replaced with Exclude<keyof T, symbol> (which is still a problem for other use cases).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the generic indexed-access cases in the linked TypeScript Playground, comparing them with the allowed and non-generic examples in the issue. Trace the compiler's handling of template literal types derived from keyof T; done means the restricted template literal forms are accepted as indexed access types without regressing the listed disallowed cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100