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

如何阻止TypeScript合并联合类型对象,实现精确单类型匹配

问题说明

TypeScript 采用结构化子类型规则,原生联合类型A | B | C的校验逻辑是「对象只要满足任意一个成员类型的必填属性要求即可通过」,不会拦截额外属性。示例中的{a:1, b:2}同时满足TA(存在值为1的属性a)、TB(存在值为2的属性b)的结构要求,因此不会被类型系统拦截。

解决方案

方案1:通用精确联合工具类型(无需修改原类型)

你可以定义一个泛型工具类型,自动为联合的每个成员补充「其他成员独有的属性必须为never」的约束,从根本上禁止跨成员属性同时存在:

/**
 * 将普通联合类型转换为精确匹配的排他联合类型
 * 仅允许完全匹配联合中某一个成员的结构,禁止跨成员属性混合
 */
type ExactUnion<T, UnionRef = T> = T extends unknown
  ? T & Partial<Record<Exclude<keyof UnionRef, keyof T>, never>>
  : never;

使用时直接用该工具类型包装原有联合即可:

type TA = { a: 1 }
type TB = { b: 2 }
type TC = { c: 3 }

type StrictABC = ExactUnion<TA | TB | TC>;

// 以下写法均合法
const case1: StrictABC = { a: 1 };
const case2: StrictABC = { b: 2 };
const case3: StrictABC = { c: 3 };

// 以下写法会抛出类型错误,b属性不允许出现在匹配TA的结构中
const case4: StrictABC = {
  a: 1,
  b: 2
};

注意:该工具类型默认只做第一层属性的精确校验,如果类型包含嵌套对象,需要递归实现深层的never约束才能覆盖所有场景。

方案2:可辨识联合(业务场景推荐)

如果你的业务场景允许修改原有类型定义,给每个类型加一个互斥的字面量标识字段(即辨识符),TypeScript 会自动基于辨识符做类型收窄,天然拦截多余属性:

type TA = { type: 'TA', a: 1 }
type TB = { type: 'TB', b: 2 }
type TC = { type: 'TC', c: 3 }

type TaggedABC = TA | TB | TC;

// 合法
const valid: TaggedABC = { type: 'TA', a: 1 };
// 报错:当type为'TA'时,不允许存在b属性
const invalid: TaggedABC = { type: 'TA', a: 1, b: 2 };

这种方式语义更清晰,调试和类型收窄的体验更好,是实际项目中处理互斥对象类型的首选方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:48:19