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

TypeScript如何实现联合类型参数排他校验 阻止传入交叉属性对象

TypeScript联合类型非法传参拦截方案

问题现象

TypeScript默认采用结构类型(鸭子类型)检查机制,使用普通联合类型Teacher | Student作为参数类型时,无法拦截同时包含两个类型独有字段的非法传参,复现代码如下:

interface Teacher {
  age: number
  salary: number
}
interface Student {
  age: number
  classes: string
}

type Person = Teacher | Student

function getAge(person: Person) {
  return person.age
}

getAge({age: 34, salary: 1000}) // 校验通过,符合Teacher类型
getAge({age: 16, classes: '5-4'}) // 校验通过,符合Student类型
getAge({age: 20, salary: 1000, classes: '5-4'})  // 预期报错,实际校验通过

出现该现象的核心原因是:普通联合类型仅要求传入值满足联合中任意一个成员的结构要求,结构类型规则允许对象持有目标类型未声明的额外字段;当额外字段恰好属于联合的其他成员时,TS默认不会判定为类型错误。

实现方案

要拦截同时持有多个联合成员独有字段的传参,需要将普通联合改造为互斥联合,有两种常用实现方式:

  • 方案1:使用可辨识联合(官方推荐)
    为联合的每个类型添加一个值唯一的判别字段,TS可以通过该字段明确区分对象所属的类型,自动拦截字段混用的情况:
    interface Teacher {
      role: 'teacher' // 独有判别字段
      age: number
      salary: number
    }
    interface Student {
      role: 'student' // 独有判别字段
      age: number
      classes: string
    }
    
    type Person = Teacher | Student
    
    function getAge(person: Person) {
      return person.age
    }
    
    // 以下非法调用会直接触发类型错误
    getAge({role: 'teacher', age: 20, salary: 1000, classes: '5-4'})
    
  • 方案2:无额外字段的互斥类型实现
    如果不想新增判别字段,可以通过工具类型结合never类型,强制要求非共有字段如果出现就必须是never类型(即不允许出现),实现字段互斥:
    // 互斥联合工具类型
    type MutuallyExclusive<T, U> =
      | (T & Partial<Record<Exclude<keyof U, keyof T>, never>>)
      | (U & Partial<Record<Exclude<keyof T, keyof U>, never>>)
    
    interface Teacher {
      age: number
      salary: number
    }
    interface Student {
      age: number
      classes: string
    }
    
    type Person = MutuallyExclusive<Teacher, Student>
    
    function getAge(person: Person) {
      return person.age
    }
    
    // 同时传入salary和classes会触发类型错误
    getAge({age: 20, salary: 1000, classes: '5-4'})
    

内容的提问来源于stack exchange,提问作者KOO

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:06:23