You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:22:36