我在编译以下内容时遇到问题。它包含在一个旧项目中,带有注释-“这是TS1.8功能。保留它以确保环境运行正确的ts”。
function assign<T extends U, U>(target: T, source: U): T {
for (let id in source) {
target[id] = source[id]; // error TS2322: Type 'U[Extract<keyof U, string>]' is not assignable to type 'T[Extract<keyof U, string>]'.
}
return target;
}
我正在使用以下命令对其进行编译
tsc -p tsconfig.json
还有tsconfig.json
{
"include": [
"Scripts/TypeScripts/**/*"
],
"compilerOptions": {
"target": "es5",
"module": "amd",
"sourceMap": false,
"watch": false
}
}
tsc -v
产生Version 3.4.5
。
当我try it in the playground时,我还看到错误,这使我认为它确实是无效的代码。但是,这提出了一个问题,当我编写该评论时,我在想什么,以及它为什么已经编译了两年(或已经编译?)
所以-我的问题:这是有效的TS代码吗?如果没有,那有没有?
谢谢:-)
答案 0 :(得分:2)
这对我来说似乎无效,但是我没有使用TS1.8(我认为我从2.4左右开始)。使用T extends U
的问题在于,尽管U
的所有属性键也必须存在于T
中,但这些属性键的 values 可能是< em>更窄。也就是说,鉴于此:
function badAssign<T extends U, U>(target: T, source: U): T {
for (let id in source) {
target[id] = source[id] as any; // assert to remove error, but
}
return target;
}
您可以这样做:
interface Ewe {
w: string;
x: number;
y: boolean;
}
interface Tee extends Ewe {
w: "hey";
x: 1;
y: true;
z: object;
}
const t: Tee = { w: "hey", x: 1, y: true, z: {} };
const u: Ewe = { w: "you", x: 2, y: false };
const newT = badAssign(t, u); // compiles, but
newT.w // "hey" at compile time, "you" at runtime !!
newT.x // 1 at compile time, 2 at runtime !!
newT.y // true at compile time, false at runtime !!
这很糟糕...通过将source[id]
分配给target[id]
,您假设target[id]
的属性类型与该类型相同或宽于 source[id]
的值,但当T extends U
时则相反:target[id]
与source[id]
的类型相同或窄于。因此,您不得不对编译器撒谎。
我要解决的方法是将U
替换为Pick<T, K>
,并将K
扩展为keyof T
。这样可以确保target
的每个键都像以前一样存在于source
上,此外,还可以保证target
的每个键都可以分配source
的相应属性的值对此:
function assign<T, K extends keyof T>(target: T, source: Pick<T, K>): T {
for (let id in source) {
target[id] = source[id]; // okay
}
return target;
}
这捕获了错误呼叫的错误:
assign(t, u); // now an error, string is not assignable to "hey"
但是仍然可以按照预期的目的使用assign()
:
let target = { a: "hey", b: 123, c: true };
let source = { a: "you", c: false };
const ret = assign(target, source);
好的,希望能有所帮助;祝好运!
答案 1 :(得分:1)
我猜想,如果使用TypeScript 通过v1.8的“ TypeScript新增功能”小节“ Type parameters as constraints”: 使用TypeScript 1.8,可以使用类型参数
从相同类型参数引用类型参数的约束
清单。以前这是一个错误。此功能通常是
称为F界多态性。
Example
function assign<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 };
assign(x, { b: 10, d: 20 });
assign(x, { e: 0 }); // Error