首页 > 解决方案 > 在 TypeScript 中复制相同键属性错误

问题描述

TypeScript 中使用相同的键类型将属性从源复制到目标的正确方法是什么?

interface ITest {
    first?(val: number, msg: string): void;
    second?(): void
}

function copy(e: keyof ITest, source: ITest, dest: ITest) {
    // TS2322:
    // Type '(val: number, msg: string) => void' is not assignable to type '() => void'.
    dest[e] = source[e];
}

我不明白为什么 TypeScript 看不到源和目标是相同的类型并且我们使用相同的键类型。但是我们应该怎么做呢?


我正在使用 TypeScript 3.6.4,tsconfig.json如下所示:

"compilerOptions": {
  "module": "commonjs",
  "target": "es6",
  "strict": true
 }

标签: typescript

解决方案


TS3.5 引入了一项更改,以在写入键为联合的属性时强制执行更多类型安全。仅就types而言,编译器无法区分您要执行的操作与此处绝对不安全的代码之间的区别:

function badCopy(k1: keyof ITest, k2: keyof ITest, o: ITest) {
  o[k2] = o[k1]; // error!
}

在这里,keyk1k2类型完全相同:keyof ITest. 但是很有可能您正试图盲目地将一个属性从一个键复制到另一个键的不兼容属性。因为and中的键值可能不一样,尽管是相同的类型。这是不安全的,所以你会得到一个错误。k1k2


不幸的是,即使您确定e读取和写入中的值完全相同,该更改也会导致您正在做的事情被视为“可能不安全”。这目前被认为是 TypeScript 中的设计限制,尽管他们可能会考虑特殊大小写相同的密钥标识符。如果你关心这一点,你可能想去相关的 GitHub 问题(看起来microsoft/TypeScript#32693仍然被列为“讨论中”)并给它一个或描述你的用例,如果它比列出的更引人注目那里。


话虽这么说,但除非得到解决,否则有一些解决方法:

只要编译器看不到您使用联合类型作为键类型,编译器仍然允许将相同类型分配给自身的漏洞。通常你可以让你的函数更通用,像这样:

function copy<K extends keyof ITest>(e: K, source: ITest, dest: ITest) {  
  dest[e] = source[e]; // no error now
}

或者,如果您不想这样做,只需接受您比此处的编译器更了解并使用类型断言告诉它不要担心:

function copyAssert(e: keyof ITest, source: ITest, dest: ITest) {
  dest[e] = source[e] as any; // one way
  dest[e] = source[e] as ITest["first"] & ITest["second"]; // more explicit 
}

希望其中之一对您有用。祝你好运!

链接到代码


推荐阅读