将 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 次 |
最近记录: |