typescript - 为什么 TypeScript 不能推断出相同对象类型的赋值?
问题描述
假设我有一个非常简化的示例来说明我的代码中发生的事情:
interface I {
n?: number;
s?: string;
}
const a: I = {
n: 1,
}
const b: I = {
n: 2,
s: 'b',
}
const props = ['n', 's'] as const;
for (const prop of props) {
if (!a[prop]) {
// here, I get the following error:
// TS2322: Type 'string | number' is not assignable to type 'never'.
// Type 'string' is not assignable to type 'never'.
a[prop] = b[prop];
}
}
存在a
和b
相同的类型,访问相同的属性prop
......这不是可能的吗?
- 如果
b[prop]
是一个数字,那么a[prop]
应该接受数字 - 如果
b[prop]
是字符串,那么a[prop]
应该接受字符串 - 如果
b[prop]
未定义,是因为该道具是可选的?
那么,我在这里缺少什么?
更新:由于我简化了我的例子太多,答案是删除as const
部分......但我认为这是由于我的环境,因为我正在strict: true
使用tsconfig.json
......
然后,如果我尝试在没有 的情况下访问as const
,我会收到 TS7053 错误:
元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型“I”。
在“I”类型上未找到具有“字符串”类型参数的索引签名。
修复添加as const
或做for(const prop of props as ('n' | 's')[]) {
然后是当我得到我原来的错误时(可以很容易地修复,as any
但我试图避免这种情况)
解决方案
一般来说,Typescript 不会证明代码的所有可证明属性,也不会尝试证明。在这种特殊情况下,我们人类知道类型与类型b[prop]
匹配,a[prop]
因为属性名称相同,但 Typescript 看不到这一点,因为它没有允许它的规则。
如果我们按照 Typescript 的逻辑:
props
被声明为类型的元组['n', 's']
。prop
被声明为 的元素props
,因此其类型被推断为'n' | 's'
。- 由于
b
被声明为 typeI
, thenb[prop]
被推断为 typeI['n' | 's']
简化为string | number
。 - 由于
a
被声明为 typeI
,那么赋值目标a[prop]
只能接收一个可赋值给任何prop
可能命名的属性的值;因此,分配目标的类型被推断为I['n'] & I['s']
简化为string & number
,然后never
。 - 就 Typescript 而言,赋值
a[prop] = b[prop]
是将 type 的值赋给 typestring | number
的赋值目标never
。由于string | number
不可分配给never
,这是一个类型错误。
最简单的解决方法是使用类似的类型断言b[prop] as any
,即告诉 Typescript 你知道你的代码是类型安全的,因此不需要检查它。另一种选择是使用辅助函数,它以满足 Typescript 类型检查器的方式进行分配:
function copyMissingProperties<T>(a: T, b: T, props: readonly (keyof T)[]): void {
for (const prop of props) {
if (!a[prop]) {
a[prop] = b[prop]; // ok
}
}
}
这里,prop
' 的类型keyof T
不是联合类型,因此赋值目标没有交集类型。
推荐阅读
- css - 边框速记CSS内的边框半径
- python - 在 Pandas 中将原始日期转换为年/月/星期几
- android - Flutter 如何在无状态小部件中使用生命周期事件?应用关闭
- firebase - 尝试通过 cfhttp post 发送到 Firebase FCM
- reactjs - useState Reactjs 没有更新
- php - Laravel 嵌套查询
- java - Java(Android)中的FileObserver多次触发
- image - PrestaShop 1.7.6 图像在打开友好 URL 时不显示
- forms - 仅在选中另一个下拉菜单时才使下拉选项可单击
- php - 如何对客户端系统上发现的这种潜在 PHP 恶意软件进行去混淆处理?