将 typescript 版本升级到 3.7 后,我在 2 个函数中遇到了类型错误。功能正常工作(添加@ts-ignore 时一切正常)。
interface A {
x: string,
y: number,
}
interface B {
x: string,
y: number,
z: boolean,
}
function extract(input: B, keys: Array<keyof A>): Partial<A> {
const extract: Partial<A> = {};
keys.forEach((key: keyof A) => {
extract[key] = input[key]; // error!
// ~~~~~~~~~~~~ <-- 'string | number' is not assignable to 'undefined'
});
return extract;
}
function assign(target: B, source: Partial<A>): void {
(Object.keys(source) as Array<keyof A>).forEach((key) => {
target[key] = source[key]!; // error!
// ~~~~~~~~~~~ <-- 'string | number' is not assignable to type 'never'
});
}
const test: B = { x: "x", y: 1, z: true };
console.log(extract(test, ["y"])); // -> { y: 1 }
assign(test, { x: "new" });
console.log(test); // -> { x: "new", y: 1, z: true }
Run Code Online (Sandbox Code Playgroud)
代码和错误可以在ts playground找到
有没有办法在没有@ts-ignore 的情况下以正确的方式实现这一点?
这是TypeScript 3.5 中引入的一个已知的重大更改,以防止对索引访问类型的不良写入。正如您所见,它通过捕获实际错误产生了一些良好的效果,并且通过对完全安全的分配发出错误警告而产生了一些不幸的影响。
解决这个问题的最简单方法是使用类型断言:
(extract as any)[key] = input[key];
(target as any)[key] = source[key];
Run Code Online (Sandbox Code Playgroud)
有比 更安全的断言any,但表达起来更复杂。
如果要避免类型断言,则需要使用一些变通方法。对于extract(),在 内部使用通用回调函数就足够了forEach()。编译器将赋值视为来自和指向相同泛型类型的值Partial<A>[K],它允许:
function extract(input: B, keys: Array<keyof A>): Partial<A> {
const extract: Partial<A> = {};
keys.forEach(<K extends keyof A>(key: K) => {
extract[key] = input[key];
});
return extract;
}
Run Code Online (Sandbox Code Playgroud)
对于assign()这target[key] = source[key]不会与通用甚至工作key类型K。您正在读取泛型类型NonNullable<Partial<A>[K]>并写入不同的泛型类型B[K]。(我的意思是“不同”,因为编译器不会以相同的方式表示它们;当然,当您评估它们时它们是相同的类型。)我们可以通过将target变量扩大到Partial<A>(这很好,因为每个B也是一个Partial<A>,如果你眯着眼睛不考虑突变)。
所以我会这样做:
function assign(target: B, source: Partial<A>): void {
const keys = Object.keys(source) as Array<keyof A>;
const widerTarget: Partial<A> = target;
keys.forEach(<K extends keyof A>(key: K) => {
if (typeof source[key] !== "undefined") { // need this check
widerTarget[key] = source[key];
}
});
}
Run Code Online (Sandbox Code Playgroud)
哦,我添加了该undefined支票,因为assign(test, { x: "new", y: undefined })是允许的;该语言并没有真正区分缺失与undefined.
无论如何,这些将按需要工作。就我个人而言,我可能只是使用类型断言并继续前进。
好的,希望有帮助;祝你好运!
| 归档时间: |
|
| 查看次数: |
3774 次 |
| 最近记录: |