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

如何让TypeScript禁止联合类型包含其他变体的字段?

如何让TypeScript禁止联合类型的值包含所有变体的字段?

给定如下场景:

type Foo = {
  foo: string;
};

type Bar = {
  bar: string;
};

type MyUnion = Foo | Bar;

// 当前是允许的,但希望被禁止
const x: MyUnion = { foo: "", bar: "" };

我希望TypeScript能检测出,MyUnion类型的值同时包含foo和bar字段是不被允许的。

目前我知道两种实现方式:

方式a:转换为区分联合类型

type Foo = {
  _type: "foo";
  foo: string;
};

type Bar = {
  _type: "bar";
  bar: string;
};

type MyUnion = Foo | Bar;

// 现在会被禁止,符合预期
const x: MyUnion = { _type: "foo", foo: "", bar: "" };

方式b:显式禁止其他变体的字段

type Foo = {
  foo: string;
  bar?: undefined;
};

type Bar = {
  bar: string;
  foo?: undefined;
};

type MyUnion = Foo | Bar;

// 现在会被禁止,符合预期
const x: MyUnion = { foo: "", bar: "" };

是否存在不依赖这两种方法的其他实现方式?


当然有,你可以通过构造排除多余字段的约束类型来实现,核心思路是让联合类型的每个变体仅能包含自身必填字段,禁止出现其他变体的字段。

方案1:通用工具类型StrictUnion

可以编写一个通用工具类型,自动为联合类型的每个成员排除其他成员的字段:

type StrictUnion<T> = T extends any 
  ? T & Partial<Record<Exclude<keyof (StrictUnion<T>), keyof T>, never>> 
  : never;

// 原类型定义保持不变
type Foo = { foo: string };
type Bar = { bar: string };

// 用StrictUnion包装原联合类型
type MyUnion = StrictUnion<Foo | Bar>;

// 触发报错:类型"{ foo: string; bar: string; }"无法赋值给"StrictUnion<Foo | Bar>"
const x: MyUnion = { foo: "", bar: "" };

// 合法赋值不受影响
const y: MyUnion = { foo: "" };
const z: MyUnion = { bar: "" };

这个工具类型的逻辑是:

  1. 遍历联合类型的每个成员T
  2. 提取该成员的所有键keyof T,排除联合类型中其他成员的键
  3. 将这些排除的键定义为never类型,明确禁止这些字段存在

方案2:直接交叉禁止字段(简化版)

如果联合类型成员数量不多,也可以直接为每个成员交叉一个禁止其他字段的类型,语义更直观:

type Foo = { foo: string } & { bar?: never };
type Bar = { bar: string } & { foo?: never };

type MyUnion = Foo | Bar;

// 触发报错:类型"{ foo: string; bar: string; }"无法赋值给"MyUnion"
const x: MyUnion = { foo: "", bar: "" };

这种方式和你提到的方式b类似,但用never替代undefined,更清晰地表达“该字段不允许存在”的语义,而非“可选为undefined”。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 20:22:18