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

TypeScript如何实现互斥属性类型并解决多余属性检查问题?

TypeScript 排他联合类型问题解决

问题背景

现有基础类型:

type Base = {
  mandatoryProperty: number
}

需要创建Full类型,要求必须包含mandatoryProperty,且只能包含property1: number或property2: number中的一个,预期结构为:

type Full = {
  mandatoryProperty: number
  property1: number
} | {
  mandatoryProperty: number
  property2: number
}

最初实现的工具类型Combined:

type Combined<T, V> = {
  [K in keyof V]: {[R in keyof T]: T[R]} & { [P in K]: V[P] }
}[keyof V]

通过type Full = Combined<Base, {property1: number, property2: number}>定义后,发现可以同时赋值property1和property2:

const X: Full = {
  mandatoryProperty: 3,
  property1: 2,
  property2: 4 // 未触发报错,不符合预期
}

问题1:最初的Combined为什么允许同时存在两个属性?

这不是多余属性检查的问题,核心原因是TypeScript联合类型的匹配规则:当一个对象同时满足联合类型的多个分支时,TypeScript会判定它符合该联合类型。

最初的Combined生成的Full类型是:

(Base & {property1: number}) | (Base & {property2: number})

同时包含property1和property2的对象,既满足第一个分支(拥有mandatoryProperty和property1),也满足第二个分支(拥有mandatoryProperty和property2),因此TypeScript不会报错。


问题2:修改后的带never的Combined为什么无效?

你修改后的代码:

type Combined<T, V> = {
  [K in keyof V]: {[R in keyof T]: T[R]} & { [S in keyof V]: S extends K ? V[K] : never }
}[keyof V];

无效的原因主要有两点:

  1. 语法逻辑错误:S extends K ? V[K] : never应改为S extends K ? V[S] : never——虽然当前场景下V[K]和V[S]都是number,类型结果一致,但写法逻辑错误,若V的不同属性类型不同时会直接出错。
  2. 必选never属性的矛盾:该类型生成的分支要求必须提供所有V的属性,其中非目标属性的类型是never,但never类型没有合法值,TypeScript在类型检查时会出现逻辑偏差,部分旧版本TS不会触发预期的报错。

正确的解决方案

要实现严格的排他联合类型,需要在每个分支中明确禁止其他属性存在,可以通过将非目标属性设为可选的never类型来实现:

type Combined<T, V> = {
  [K in keyof V]: 
    T & 
    Pick<V, K> & 
    Partial<Record<Exclude<keyof V, K>, never>>
}[keyof V]

代码解释

  • Pick<V, K>:仅保留V中的当前属性K
  • Partial<Record<Exclude<keyof V, K>, never>>:将V中除K外的其他属性设为可选且类型为never——一旦给这些属性赋值,就会触发类型错误
  • 最终生成的Full类型为:
    (Base & {property1: number} & {property2?: never}) | (Base & {property2: number} & {property1?: never})
    

验证效果

此时再尝试同时赋值两个属性:

const X: Full = {
  mandatoryProperty: 3,
  property1: 2,
  property2: 4 // 报错:类型“number”不能赋值给类型“never”
}

完全符合预期,仅允许存在property1或property2中的一个。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 02:59:55