Reputation:
I want to create new types, rather than transform a specific one, below is my code:
type CustomMapped<K extends any , T> = { //can't compile
[P in K]: T
};
it doesn't compile, and the error is :
Type K is not assignable to type 'string | number | symbol'
so I have to add keyof
in front of any as:
type CustomMapped<K extends keyof any , T> = ... //can compile
I'm confused, if I rewrite the code as:
type CustomMapped<K extends string | number | symbol, T> = { //also compile
[P in K]: T
};
it compiles, so it means Type K is assignable to type string | number | symbol
so why the original error says Type K is not assignable to type string | number | symbol
, and why I added keyof
then it is OK?
Upvotes: 1
Views: 116
Reputation: 5650
The in
operator works to create mapped types.
It expects a union of strings, number or symbols to effectively iterate through. As demonstrated in the documentation:
type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]: boolean };
K
will become option1
on the first "iteration" and option2
on the second. However, if Keys
were an object, this wouldn't work.
type Keys = { option1: any; option2: any };
type Flags = { [K in Keys]: boolean };
// ^^^^
// Type 'Keys' is not assignable to type 'string | number | symbol'.
Because Keys
is not a string
, number
or symbol
to iterate over, but an object. Since we want to iterate over the keys, this can be solved with the keyof
operator to return 'option1' | 'option2'
.
With your example, you can update this with [P in keyof K]
which will evalue to [P in 'option1' | 'option2']
and work as expected:
type CustomMapped<K extends any, T> = { [P in keyof K]: T };
Upvotes: 1