Typescript类型收窄无法正确解析对象属性类型问题
问题产生原因
这个报错是TypeScript控制流分析的类型收缩(Narrowing)机制的限制导致的:
- 你在if分支中仅对
obj.prop这个单独属性做了非空、类型校验,TypeScript只会收缩obj.prop这个属性自身的类型,不会自动把整个obj对象的类型从Wide收窄为Narrow。 - 当你使用扩展运算符
...obj构造新对象传入Foo构造函数时,TypeScript仍然会按照Wide类型来解析obj,认为它的prop属性是string | undefined类型,不符合Narrow接口的要求,因此抛出类型错误。
额外说明:你写的if校验存在冗余,obj.prop && typeof obj.prop === 'string'已经可以完全排除undefined的情况,不需要额外判断obj.prop !== undefined。
解决方案
提供几种常用的修复方案,可根据场景选择:
方案1:直接传入校验后的属性(最推荐)
直接传递已经完成类型校验的prop属性,不要扩展整个obj对象,TypeScript可以正确识别obj.prop已经被收缩为string类型:
array.forEach((obj: Wide) => { if (typeof obj.prop === 'string') { console.log(new Foo({ prop: obj.prop })) } })
方案2:使用类型守卫收窄整个对象类型
如果需要频繁判断Wide类型是否符合Narrow的要求,可以编写自定义类型守卫,触发TypeScript对整个对象的类型收窄:
// 自定义类型守卫 function isNarrow(obj: Wide): obj is Narrow { return typeof obj.prop === 'string' } array.forEach((obj: Wide) => { if (isNarrow(obj)) { console.log(new Foo({ ...obj })) // 此时obj类型已经被收窄为Narrow,不会报错 } })
方案3:使用类型断言跳过校验
如果你100%确定当前场景下obj的prop属性已经是string类型,可以用类型断言直接告诉TypeScript按照Narrow类型处理:
array.forEach((obj: Wide) => { if (typeof obj.prop === 'string') { console.log(new Foo({ ...obj } as Narrow)) } })
内容的提问来源于stack exchange,提问作者Donald Zhu
相关产品推荐
相关产品推荐

