-
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
Can't remap tuple keys to object keys in mapped types #55762
Comments
May be related to #27995. Workaround: Do not use type KeyofTuple<T extends readonly any[]> =
Exclude<keyof T, keyof []> extends infer StringIndex
? StringIndex extends `${infer NumericIndex extends number}`
? NumericIndex
: never
: never; type StructTypeFor<Descriptor extends StructDescriptor> = {
- [K in (keyof Descriptor) & number as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
+ [K in KeyofTuple<Descriptor> as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
}; |
I think that perhaps this could work (but it doesn't): type StructTypeFor<Descriptor extends StructDescriptor> = {
[K in keyof Descriptor as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
}; I might play with implementing a change that would allow this if I find the time for this next week. |
You should use type StructTypeFor<Descriptor extends StructDescriptor> = {
[K in keyof Descriptor & `${number}` as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
}; |
My own understanding of what is going on so far: We have a mapped type called Depending on how you write the mapped type
type StructTypeFor<Descriptor extends StructDescriptor> = {
[K in (keyof Descriptor) & number as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
}; Then, when we resolve the mapped type with
This union, when intersected with The result is that the type of
type StructTypeFor<Descriptor extends StructDescriptor> = {
[K in (keyof Descriptor) & `${number}` as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
}; then roughly the same will happen, except The result is that the type of
type StructTypeFor<Descriptor extends StructDescriptor> = {
[K in keyof Descriptor as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
}; then you get errors on Ignoring that error, then what happens is similar to to the first case, except that Some things I don't understand or that bother me here:
Footnotes
|
I suspect that not having that would result in some questionable DX: const tuple = ['', 10] as const
function getX(i: number) {
return tuple[i] // would be an error
} For improved type safety of this access, you can opt into
This βοΈ That's why I decided to open my PR - with it you don't even need to use an intersection so I think it's an improvement since one doesn't have to even consider what's the correct way to do this intersection. They can just use the builtin language features to achieve the desired outcome.
That's (kinda) what I tried in #48599 and that PR ultimately led to #48837
Yes, from that PoV TypeScript representation is correct. I don't think it's super pragmatic though :P but certainly, there are also other considerations here beyond just arrays. number/string indexers have at times weird behaviors/overlaps between each other.
It's worth noting that then arrays/tuples would have to have both index signatures because |
I think for now we don't really want to change the rules regarding (homomorphic) mapped types instantiated with array or tuple types. There's already a way to express what this issue asks for, as suggested above:
The current rule we have landed on is to instantiate mapped types with array and tuple types in a special way when the mapped type is homomorphic and has no type Mapped<T> = { [K in keyof T]: SomeType<T, K> };
type MappedTuple = Mapped<[1, 2, 3]>; // [SomeType<T, K>, SomeType<T, K>, SomeType<T, K>] then only the element properties of the type are considered when mapping (e.g. I think this rule makes it clear when the "array-ness" of the input type is preserved by a mapped type, and it does what users expect. Compare that to when a mapped type is homomorphic but has an In the issue's example: type StructTypeFor<Descriptor extends StructDescriptor> = {
[K in (keyof Descriptor) & number as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
}; when instantiating mapped type type StructTypeFor<Descriptor extends StructDescriptor> = {
[K in keyof Descriptor as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
}; (see also #58237 (comment)) |
I agree with @gabritto 's reasoning - if this is solvable today, and the proposed fix would make things harder to understand, then the best thing to do is to stick with the current behavior. We can reevaluate in a new issue if unsolvable use cases appear. |
This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
π Search Terms
mapped tuple, mapped types
π Version & Regression Information
β― Playground Link
https://www.typescriptlang.org/play?ts=5.2.2#code/CYUwxgNghgTiAEkoGdnwCLgPahgHgBUA+eAbwCh4r5QwcQAKWGKATwCEBXAM25BgBc8AIIwWHHnxgBKIQQDc5AL7lyAF1YAHBADUoETiAJaQAeW6F4IAB5qQAO2BpMdXHij3WREgF54BK1sHJwxsNwBLeyl4ACUSAH5Y+CF7EAA3fkV1E3gAZTUYTjA1TGQwGHDNNSwYeD8YkChgLHsIVlFxPDgmlrb4AG0AaxBWIWQCyIBzABp4DW0hF3p8Dy8AXSIs+YR8wuLjbQAxGrxS8srq2ps7RzRdopKQMoqqmt8ySmp+gGl4SPgGMNWFhuKFnhcatJ4AAyeD2TgAWwARvx4CgwedXjAfmt+gAGNZrIR6AxGEzmU5PTGXHH9ACMG0USiySFQeQKDyWbjo9nGGJel0CNxC92KZwFbyFwWcYX4eFFagOIGO+HFEJg3g+1EQLXGe0uDFA4KxiypEpkWu11GQnG0MAY0kU2pUKnItGgcB1vLUfwAzAAmLn8U2uOXw5H8TZu8AehA8vnhABsABYg4JQqH8EjwpNImoo+R4z69ZzZbU-KkAO7s-Vphj9T5UfoAIigzdm4QDabW00bA2bSPbfxT3d7a0dqiL8BLxTq045YrLADpaPQGFWRGI2FxePwGHS8XjpBPC7qfWkUoiUeX5-ql1BFEA
π» Code
π Actual behavior
The type of
struct.a
has typenumber | bigint
, however it should only have typenumber
.π Expected behavior
struct.a
should have typenumber
(and similarlystruct.b
should have typebigint
).Additional information about the issue
This does work when using a record instead, however this isn't as useful as I want the descriptor to still be an array so I can iterate over it.
The text was updated successfully, but these errors were encountered: