typescript - 受约束的泛型函数中令人困惑的“[ts] Type ... 不可分配给类型 [2322]”错误
问题描述
我一直对下面代码中的 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);
}
如果类型是非泛型的,类似的代码编译不会出错。
function works() {
interface A {a: number};
const foo: A = {a: 1}; // no compiler error, as expected
console.log (foo);
}
为什么第一个函数编译失败?我假设我对接口和通用约束之间的区别有一些基本的误解。
解决方案
过了一会儿,我意识到了问题所在。将 TypeScript 错误 2322 翻译成简单的英文,它的意思是:“您正在尝试将 的值设置为仅具有数字属性的对象文字,该值A
具有数字属性a
但也可能具有其他属性 (!!!)a
. 因为这个对象字面量缺少 A 的其他(潜在)属性,所以赋值失败。 ”
作为问题的说明,想象用一个真实类型替换 A:
interface A { a: number; b: string; };
const foo: A = { a: 1 }; // compiler error, as expected
a
如果泛型类型是特定类型,则如果满足泛型约束(“具有数字属性”)的任何可能类型都可以工作,则编译器将引发错误。
理论上,TypeScript 在这种情况下可能会更聪明,方法是检查结果是否foo
可能导致代码后期出现问题。例如,如果您唯一要做的事情foo
是使用它的a
属性,并且您不返回做任何foo
超出其约束的事情,例如将其传递给接受的其他函数A
。
但似乎 TypeScript 还没有那么聪明——它并没有考虑到你的代码的未来。相反,它在分配点检查所有可能的右侧类型是否满足左侧类型的约束。如果不是,则会引发错误。
如果您确定代码不会导致问题(例如,因为您传入的值不只是 extend A
,它实际上是的一个实例A
),那么您可以将值强制转换为 A 并且分配将起作用。这是调用数据库等外部 API 时的常见模式,它可能会返回无类型的 JSON,您可以将其转换为您知道的类型。像这样:
function alsoWorks1<A extends {a: number}>() {
const foo: A = {a: 1} as A;
console.log (foo);
}
或者您可以决定将其从通用函数更改为非通用函数。像这样:
function alsoWorks2() {
const bar = { a: 1 };
const foo = { a: bar.a }; // no error
console.log (foo);
}
推荐阅读
- excel - VBA - 如何访问 Mac Excel 上的文件夹?
- tensorflow - TensorFlow:如何在 Eager Execution 中检查梯度和权重?
- node.js - 在 Node Express 应用程序中为 Stripe 创建 webhook;发出阅读请求
- python - Python,URL NLP:如何计算 URL 字符串中的所有英文单词?
- reactjs - 如何在我的函数中使用自定义钩子?
- php - mysql select准备好的语句不发送令牌
- python - 如何使用 Python 解析和修改 .odg 文件?
- sql - 如何在查询中引用参数选择?
- javascript - 动态创建按钮时如何交出变量?
- excel - 无法弄清楚如何索引、匹配和使用表中组合的 if 函数