"Using Type Parameters in Generic Constraints" in the TypeScript site shows the example code below. But the following error occurred:
'Type 'U[keyof U]' is not assignable to type 'T[keyof U]'. Type 'U' is not assignable to type 'T'.'
function copyFields<T extends U, U>(target: T, source: U): T {
for (let id in source) {
target[id] = source[id];
}
return target;
}
let x = { a: 1, b: 2, c: 3, d: 4 };
copyFields(x, { b: 10, d: 20 });
In fact, this does not run in the Playground. What is wrong with the code?
It makes sense that U
is not assignable to T
since the object satisfying U
could have additional fields that T
doesn't have:
interface Foo { foo: number; }
interface Bar extends Foo { bar: number; }
interface Bar2 extends Foo { bar: string; }
function assign<T extends U, U>(b: U): T {
const returnVal: T = b; // error: Type 'U' is not assignable to type 'T'.
return returnVal;
}
const bar2: Bar2 = { foo: 7, bar: "happy" };
assign<Bar, Foo>(bar2);
So, since U
isn't assignable to T
, there's no way we can guarantee that a specific U[keyof U]
is assignable to T[keyof U]
.
(I'm not 100% confident in this explanation, but it seems to make sense to me.)
However, by modifying how you type things, you can write a version of copyFields
that works as intended, like this:
function copyFields<T, K extends keyof T>(target: T, source: Pick<T, K>) {
for (let id in source) {
target[id] = source[id];
}
return target;
}
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