-
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
Tuple types are not indexed by number in mapped types #48398
Comments
For the record the whole mapped types on tuples and arrays does kind've work: type Locals<Types> = {
[K in keyof Types]: Local<Types[K]>
}
function toLocals<Types extends readonly ValType[]>(valTypes: Types): Locals<Types> {
return valTypes.map(type => new Local(type)) as unknown as Locals<Types>;
}
const i32x2 = ["i32", "i32"] as const;
// This actually works now, but there's a new error above
const locals: readonly [Local<"i32">, Local<"i32">] = toLocals(i32x2); However it still reports an error in trying to wrap, essentially generics with a constraint can't be used properly in a mapped type: type Locals<Types> = {
// Type 'Types[K]' does not satisfy the constraint 'ValType'.
// Type 'Types[keyof Types]' is not assignable to type 'ValType'.
// Type 'Types[string] | Types[number] | Types[symbol]' is not assignable to type 'ValType'.
// Type 'Types[string]' is not assignable to type 'ValType'.(2344)
[K in keyof Types]: Local<Types[K]>
}
|
This is the intended behavior. Mapped types can be homomorphic but the keyof operation still uses the string names of the keys (since, even for arrays, the keys are "actually" '0', '1', '2', etc). From a caller perspective, giving you the ability to distinguish between the 0 and "0" meanings doesn't make any sense because objects can't have different property slots. |
I thought it was more about being able to distinguish between 0 and, say, "foo". That's why numeric index signatures are generally convenient, because it's harder to make that distinction otherwise. |
I know that there's not actually "number keys" in JS, but the fact is there is no other way in TypeScript to say
Arguably with template types, we should be able to do type Locals<Types extends readonly ValType[]> = {
// Type 'Types[K]' does not satisfy the constraint 'ValType'.
// Type 'Types[`${number}` & string]' is not assignable to type 'ValType'.
[K in keyof Types]: K extends `${ number }` ? Local<Types[K]> : Types[K]
} In this case, K is too wide in the Although I suppose we can do this: type Locals<Types extends readonly ValType[]> = {
[K in keyof Types]: K extends `${ number }`
? Types[K] extends ValType ? Local<Types[K]> : never
: Types[K]
} This is definitely "correct", but man is it a long and nuanced type to write just to map the usual keys of an array/tuple. Like TypeScript already offers the magic mapped array/tuple types behaviour, it would probably be simpler if this just worked for generics with constraints as well as per my second comment. Because for whatever reason adding the constraint: type Locals<Types extends readonly ValType[]> = {
[K in keyof Types]: Local<Types[K]>
} Means the mapped type no longer acts as a array/tuple-only mapped type. Alternatively alternatively, we could just have actual syntax to say some mapped type just applies to the entries in an array/tuple: type Locals<Types extends readonly ValType[]> = {
// All other keys are automatically passed through as is
[K in arrayKeys Types]: Local<Types[K]>
} |
An operator to get the numeric keys out of a type, in number form, would be a reasonable suggestion |
Like #48094? |
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
This issue was fixed by #48837. The original example now works as expected when type Locals<Types extends readonly ValType[]> = {
[K in keyof Types]: Local<Types[K]>
} |
Bug Report
π Search Terms
tuple, mapped types, number
π Version & Regression Information
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
The tuple keys are not mapped correctly as numbers. For some reason
K extends number
is never triggered for the numeric keys in["i32", "i32"]
.π Expected behavior
The mapping should set
K = 0
andK = 1
in the tuple, while it does correctly set them to"0"
and"1"
as far as I can tell there is no way to identify all "numeric like" strings in a mapped type. My assumption was the whole point of allowing "number" keys for objects was so that this kind've thing worked.Notes
The mapped types still work fine for array, i.e.
Locals<readonly ("i32")[]>
resolves just fine toreadonly Local<"i32">[]
but this functionality doesn't extend to tuples.The text was updated successfully, but these errors were encountered: