TypeScript如何收窄含联合类型属性的对象类型?
TypeScript 收窄带联合类型属性的对象类型问题解决
问题场景
我遇到了需要收窄带有联合类型属性的对象类型的场景,简化后的示例代码如下:
interface typeA{ id: number, status: 0 | 1, } interface typeB extends typeA { status: 1, } function log(param: typeB){ // 仅接受 status = 1 的参数 }
当尝试将typeA类型的数据传入log函数时,即便已经将status改为1并做了条件判断,依然会报错:
Argument of type 'typeA' is not assignable to parameter of type 'typeB'. Types of property 'status' are incompatible. Type '0 | 1' is not assignable to type '1'. Type '0' is not assignable to type '1'
对应测试代码:
const data1: typeA = {id: 1, status: 0} data1.status = 1 if(data1.status === 1){ data1.status // 鼠标悬浮时,TypeScript 可正确识别其类型为1 log(data1) // 此处报错 }
问题原因
TypeScript 对单个属性的类型收窄,不会自动同步升级整个对象的类型。data1的基础类型始终是typeA,哪怕status被条件判断收窄为1,TypeScript 也不会默认推断整个对象变成typeB——这是因为对象是引用类型,存在被其他代码修改属性的潜在风险,所以不会自动提升对象整体类型。
解决方案
1. 你当前使用的对象展开重构法
通过对象展开创建新实例,让 TypeScript 自动推断新对象的类型为typeB:
if(data1.status === 1){ log({...data1, status: data1.status}) }
这种方法的优势是无需额外语法,通过创建新对象规避了引用类型的类型限制,逻辑直观。
2. 类型断言(Type Assertion)
直接告诉 TypeScript 当前对象符合typeB类型,写法更简洁:
if(data1.status === 1){ log(data1 as typeB) }
注意:这种方式需要你确保status确实为1,因为类型断言是开发者主动覆盖 TypeScript 的类型推断,若后续逻辑变更导致status不符合预期,会带来运行时风险。
3. 自定义类型守卫(Type Predicate)
如果需要更严谨的类型检查,适合复杂场景,可以写一个类型守卫函数:
function isTypeB(obj: typeA): obj is typeB { return obj.status === 1; } // 使用方式 if(isTypeB(data1)){ log(data1); // 此处 TypeScript 会自动推断 data1 为 typeB,无报错 }
类型守卫通过obj is typeB的返回类型声明,明确告诉 TypeScript:当函数返回true时,参数的类型就是typeB,能实现最安全的类型收窄。
总结
- 简单场景下,类型断言或对象展开都可以快速解决问题
- 复杂场景或需要严格类型校验时,优先使用自定义类型守卫
内容的提问来源于stack exchange,提问作者aii-yin
相关产品推荐
相关产品推荐

