Jus*_*ant 7 typescript typescript-generics
我一直对下面代码中的 TypeScript 编译器错误 2322 感到困惑。
function broken<A extends {a: number}>() {
const foo: A = {a: 1}; // unexpected error: [ts] Type '{ a: number; }' is not assignable to type 'A'. [2322]
console.log (foo);
}
Run Code Online (Sandbox Code Playgroud)
如果类型是非泛型,类似的代码编译不会出现错误。
function works() {
interface A {a: number};
const foo: A = {a: 1}; // no compiler error, as expected
console.log (foo);
}
Run Code Online (Sandbox Code Playgroud)
为什么第一个函数无法编译?我认为我误解了接口和通用约束之间差异的一些基本知识。
过了一会儿我意识到了问题所在。将 TypeScript 错误 2322 翻译成简单的英语,它的意思是:“您正在尝试将 的值A(具有数字属性,a 但也可能具有其他属性(!!!))设置为仅具有数字属性的对象文字a.因为这个对象字面量缺少 A 的其他(潜在)属性,所以赋值失败。 ”
作为问题的说明,想象一下用实数类型替换 A:
interface A { a: number; b: string; };
const foo: A = { a: 1 }; // compiler error, as expected
Run Code Online (Sandbox Code Playgroud)
a如果泛型类型是特定类型,则任何满足泛型约束(“具有数字属性”)的可能类型都可以工作,则编译器会抛出错误。
理论上,在这种情况下,TypeScript 可能会更聪明,因为它会检查结果是否foo可能会在代码中引起问题。例如,如果您唯一做的事情foo就是使用它的a属性,并且您不返回做任何foo超出其约束的事情,例如将其传递给接受的其他函数A。
但 TypeScript 似乎还没有那么智能——它没有考虑代码的未来。相反,它在赋值时检查所有可能的右侧类型是否满足左侧类型的约束。如果不是,则会抛出错误。
如果您确定代码不会导致问题(例如,因为您传入的值不仅仅是扩展A,它实际上是 的实例A),那么您可以将该值转换为 A 并且赋值将起作用。这是调用数据库等外部 API 时的常见模式,它可能会返回非类型化 JSON,您可以将其转换为您知道的类型。像这样:
function alsoWorks1<A extends {a: number}>() {
const foo: A = {a: 1} as A;
console.log (foo);
}
Run Code Online (Sandbox Code Playgroud)
或者您可以决定将其从通用函数更改为非通用函数。像这样:
function alsoWorks2() {
const bar = { a: 1 };
const foo = { a: bar.a }; // no error
console.log (foo);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6930 次 |
| 最近记录: |