我想编写一个类型安全的 getter,它也可能返回一些修改后的值(但我认为仍然是合理的)。
class Foo {
a: number;
b: boolean;
}
function getProp<K extends keyof Foo>(o: Foo, p: K): Foo[K] {
switch (p) {
case 'a':
return 1;
case 'b':
return o[p];
}
return undefined;
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我想getProp返回Foo[K]以便 inconst v = getProp(f, 'a') v是类型number。但是,代码在我返回的地方抛出一个错误,1因为它不能分配给never.
请注意,这在 Typescript 3.4 中有效,因为“修复了对索引访问类型的不健全写入”(https://devblogs.microsoft.com/typescript/annoucing-typescript-3-5/)。
我如何最好地编写此代码但不编写return 1 as any?
是的,自 TypeScript 3.5 发布以来,此问题已被频繁报告。正如您所指出的,索引访问的改进健全性是一个突破性的变化,它捕获了许多实际的错误,但不幸的是,也警告了相当安全的代码,例如您正在做的事情。
在这一点上,潜在的问题是扩展联合的泛型类型参数不会通过控制流分析变窄(请参阅microsoft/TypeScript#24085)。编译器没有办法说,既然p可以缩小到"a",那么类型参数K应该缩小到"a"。一般来说它不应该被允许这样做,因为K可能永远是"a" | "b"。该语言目前缺少一些允许安全发生的功能(例如,如果K可以说 not toextends "a" | "b"但相反,它必须是or but not ,那会有所帮助)。extends_oneof "a" | "b""a""b""a" | "b"
现在有解决方法和重构。@TitianCernicova-Dragomir 给出的答案是一种可能的解决方法,使用单调用签名重载函数从本质上将实现内部的行为恢复到 TS3.4 及更低版本中完成的检查。是的,它不安全;这就是 TS3.5 修复的内容。其他涉及类型断言或其他不良行为的变通方法也应该有效。
我想添加这个答案的唯一原因(除了提供上面的链接)是提到一个可以帮助的重构,这取决于你的用例。这个想法是完全忘记控制流变窄,因为编译器不能为泛型做到这一点。相反,您应该返回一些编译器可以识别为合法的东西Foo[K],方法是使用 typeFoo键对 type对象进行索引K。毕竟,索引一个对象是,如果你眯着眼睛看它,就像switch在键上做一个:
function getProp<K extends keyof Foo>(o: Foo, p: K): Foo[K] {
return { a: 1, b: o.b }[p];
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
194 次 |
| 最近记录: |