Let's say we have TypeScript code that looks like:
type User = {
id: number,
name: string,
}
let user1: User = {id: 123, name: "Hello"};
let user2: User = {id: 456, name: "World"};
let keys: (keyof User)[] = ["id", "name"];
for (let key of keys) {
user1[key] = user2[key];
}
This gives error
Type 'string | number' is not assignable to type 'never'.
for the statement
user1[key] = user2[key];
If we change the definition of keys
to
let keys: string[] = ["id", "name"];
the error goes away, but we lose type safety.
Is there some way we can avoid this error while still maintain type safety?
There is no good way to avoid a type assertion here. In recent version on TS (post 3.5 I think) when writing through an index the value written has to be compatible with all possible property values specified by the key. In your case that would be number & string
which reduces to never
hence the error.
The root cause is that TS does not keep track of variables only of types, so as far as the types are concerned, your example would be no different from:
let key1 = 'id' as keyof User;
let key2 = 'name' as keyof User;
//Obvious error
user1[key1] = user2[key2] // same error, TS can't distingusih between this and your user1[key] = user2[key]
The simplest solution is to use a type assertion if, as in your case you are sure this is ok :
type User = {
id: number,
name: string,
}
let user1: User = { id: 123, name: "Hello" };
let user2: User = { id: 456, name: "World" };
for (let key of keys) {
user1[key] = user2[key] as never
}
Play
Alternatively (but not any more type safe) you can use a small loophole where T[K]
is assignable to index value:
type User = {
id: number,
name: string,
}
let user1: User = { id: 123, name: "Hello" };
let user2: User = { id: 456, name: "World" };
let keys: (keyof User)[] = ["id", "name"];
for (let key of keys) {
set(user1, key, user2[key])
}
Play
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With