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

TypeScript是否支持对象类型的真正XOR异或联合类型?

问题核心原因解释

TS的联合类型|是常规的OR逻辑,只要值满足联合类型中任意一个成员的类型约束,就会判定为合法。同时TS的对象类型默认允许存在不在类型定义中的额外属性,仅字面量直接赋值时的「新鲜对象检查」会校验是否存在所有联合成员都不包含的未知属性,不会校验部分存在的可选组属性。
第一个示例中你定义的Props = CommonProps | (CommonProps & OptionalProps)里,props2 = {a:1, b:2, c:3}完全满足第一个分支CommonProps的约束(有a、b两个必填属性,额外的c不属于所有联合成员都不包含的未知属性,不会触发新鲜对象检查报错),因此TS判定为合法。
你之前尝试的Record<keyof OptionalProps, never>写法不生效的原因是:Record生成的是必填的c:never、d:never类型,要求这两个属性必须存在且值为never(没有任何合法值可以满足该约束),因此第一个分支实际上无法被匹配,自然起不到限制作用。

实现互斥类型的方案

要实现你要的「要么没有可选组全部属性,要么有可选组全部属性」的互斥效果,需要把禁止出现的属性定义为可选+never类型,表示该属性要么不出现,出现则必须是不可能的never类型,间接实现「不能存在该属性」的约束。

第一个示例修复代码

type CommonProps = {a:number, b: number};
type OptionalProps = {c: number, d: number};
// 定义禁止出现可选属性的分支:可选属性全部设为?never
type NoOptionalProps = { [P in keyof OptionalProps]?: never }
type Props = CommonProps & (OptionalProps | NoOptionalProps)

const props1: Props = {a: 1, b: 2};                   // 合法
const props2: Props = {a: 1, b: 2, c: 3};             // 报错:对象字面量只能指定已知属性,并且类型“Props”中不存在“c”
const props3: Props = {a: 1, b: 2, x: 3};             // 报错
const props4: Props = {a: 1, b: 2, c: 3, d: 4};       // 合法
const props5: Props = {a: 1, b: 2, c: 3, d: 4, e: 5}; // 报错

第二个示例修复代码

要实现两个可选组二选一的互斥效果,同样需要在每个分支中将另一个组的属性设为?never:

type CommonProps = {a:number, b: number};
type OptionalProps1 = {c: number};
type OptionalProps2 = {d: number};
type Props = CommonProps & (
  (OptionalProps1 & { [P in keyof OptionalProps2]?: never }) | 
  (OptionalProps2 & { [P in keyof OptionalProps1]?: never })
)

const props1: Props = {a: 1, b: 2};                   // 报错
const props2: Props = {a: 1, b: 2, c: 3};             // 合法
const props3: Props = {a: 1, b: 2, x: 3};             // 报错
const props4: Props = {a: 1, b: 2, c: 3, d: 4};       // 报错
const props5: Props = {a: 1, b: 2, c: 3, d: 4, e: 5}; // 报错

通用互斥工具类型

可以封装通用的XOR工具类型简化写法:

// 把T中属于U的属性全部设为可选never
type Without<T, U> = { [P in keyof U]?: never }
// 两个类型互斥
type XOR<T, U> = (T & Without<U, T>) | (U & Without<T, U>)

// 第一个示例用通用类型写法
type Props = CommonProps & XOR<OptionalProps, Record<string, never>>
// 第二个示例用通用类型写法
type Props = CommonProps & XOR<OptionalProps1, OptionalProps2>
类型读取效果

按上述方式定义的互斥联合类型,在读取属性时也会触发TS的类型收窄:比如判断if ('c' in props),TS会自动把props的类型收窄到带OptionalProps的分支,此时可以正常读取c、d属性;如果判断为否,则会收窄到无可选属性的分支,读取c、d会直接报错,符合你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:06:05