Skip to content

mapped tuple type indexes are strings instead of numbers #28093

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

Closed
nabbydude opened this issue Oct 24, 2018 · 3 comments
Closed

mapped tuple type indexes are strings instead of numbers #28093

nabbydude opened this issue Oct 24, 2018 · 3 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@nabbydude
Copy link

TypeScript Version: 3.2.0-dev.20181023

Search Terms: mapped tuple index string not number

Code

type MapToIndexes<T extends unknown[]> = { [P in keyof T]: P };

const Test: MapToIndexes<[any, any, any]> = [0, 1, 2];

Expected behavior: No error, typeof Test is [0, 1, 2].

Actual behavior: error TS2322: Type 'number' is not assignable to type '"0"'/'"1"'/'"2"', typeof Test is ["0", "1", "2"].

Playground Link: https://www.typescriptlang.org/play/index.html#src=type%20MapToIndexes%3CT%20extends%20unknown%5B%5D%3E%20%3D%20%7B%20%5BP%20in%20keyof%20T%5D%3A%20P%20%7D%3B%0D%0A%0D%0Aconst%20Test%3A%20MapToIndexes%3C%5Bany%2C%20any%2C%20any%5D%3E%20%3D%20%5B0%2C%201%2C%202%5D%3B

Related Issues: encountered while trying to work around #27995

Seems like for mapped tuples the pre-2.9 behaviour of all types being strings is still being applied, so for a case like

type UnBox<T extends Box<unknown>> = T extends Box<infer U> ? U : never;

type UnBoxTuple<T extends Box<unknown>[]> = {
  [P in keyof T]: P extends number ? UnBox<T[P]> : never;
};

UnBoxTuple<[Box<string>, Box<number>]> would equal [never, never] instead of the desired [string, number].

@weswigham weswigham added Bug A bug in TypeScript Domain: Mapped Types The issue relates to mapped types labels Oct 24, 2018
@ahejlsberg
Copy link
Member

This is working as intended. The property names of a tuple really are strings. For example, Object.keys([10, 20, 30]) yields ['0', '1', '2'] at run-time. Indexing with numbers really is equivalent to converting the numbers to their string representation. That said, with #23592 we allow you to declare types with numeric property names (which is then reflected as numeric literals in keyof), but it would be a breaking change to switch tuple types to use those. Not to mention the issue that numeric property names would be "swallowed" by the numeric index signature every tuple inherits from Array<T>.

@ahejlsberg ahejlsberg added Working as Intended The behavior described is the intended behavior; this is not a bug and removed Bug A bug in TypeScript Domain: Mapped Types The issue relates to mapped types labels Oct 25, 2018
@aleclarson
Copy link

aleclarson commented Oct 28, 2018

@ahejlsberg Is there a recommended way of "unboxing" the types inside a tuple, without converting the tuple into an object type? Hopefully, there's a workaround that works in v2.8+.

edit: I found #27995 which has workarounds

type Writable<T> = { -readonly [P in keyof T]: T[P] }

type WritableTuple<T extends any[]> = {
  [P in keyof T]: T[P] extends T[number] ? Writable<T[P]> : never;
};

type UnBoxed = WritableTuple<[1, ReadonlyArray<any>, 2]>
// => [1, any[], 2]

And it works in TS 2.8+ :D

@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

5 participants