← 返回题目列表

联合类型和交叉类型有什么区别?

高频 中等 第 3 / 32 题 更新于 2026/07/27
TypeScript联合类型交叉类型

简化版

联合类型 A | B 表示值可以是 A 或 B,使用时只能访问共同安全属性;交叉类型 A & B 表示同时具备 A 和 B 的能力,常用于组合对象类型。

详细版

联合类型:

type ID = string | number;

交叉类型:

type User = { id: number };
type Named = { name: string };
type NamedUser = User & Named;

联合类型需要收窄后才能访问特有属性:

function f(x: string | number) {
  if (typeof x === 'string') {
    x.toUpperCase();
  }
}

交叉类型通常用于 mixin、扩展配置、组合 props。要注意冲突属性可能变成 never

完整版教学

一、联合类型表达“多选一”

一个接口状态可能是加载中、成功、失败:

type State =
  | { status: 'loading' }
  | { status: 'success'; data: string }
  | { status: 'error'; error: Error };

当前值只会是其中一种,所以访问 data 前必须确认 status === 'success'

二、交叉类型表达“都要有”

type WithTime = { createdAt: string };
type Article = { title: string } & WithTime;

Article 必须同时有 title 和 createdAt。它适合把多个对象能力拼在一起。

三、为什么联合类型不能随便访问属性

对于 A | B,TS 只允许访问 A 和 B 都有的成员。因为运行时如果值是 B,而你访问 A 特有成员,就会出错。

所以联合类型通常要配合类型收窄。

四、交叉类型冲突问题

如果两个类型同名属性不兼容:

type X = { id: string } & { id: number };

id 可能变成 never,因为它不可能同时是 string 和 number。这类类型通常说明设计有问题。

五、面试追问与工程落地

联合类型常见追问是“为什么联合类型只能访问公共属性”。因为运行时值可能是联合中的任意一个成员,只有所有成员都拥有的属性才是安全的。想访问特有属性,必须先通过判别字段或类型守卫收窄。

交叉类型常被误解成“对象合并”。类型层面的 A & B 表示同时满足 A 和 B,但运行时不会帮你合并对象。真正合并值仍然需要 { ...a, ...b } 或其他逻辑。

工程里判别联合非常适合接口状态建模。比起多个可选字段散落在一个对象里,{ status: 'success'; data } | { status: 'error'; error } 更能让编译器帮你防止遗漏分支。

六、用值集合与可访问成员解释反直觉结果

从可能值看,A | B 扩大了可接受值集合,A & B 要求值同时满足两个约束,因此缩小了集合。但从“无需收窄即可访问的属性”看,联合只能保证各成员共有的能力,交叉则汇集双方能力;这正是很多人把两者记反的原因。

type A = { common: string; a: number }
type B = { common: string; b: boolean }
declare const union: A | B
union.common
// union.a // 报错:运行时可能是 B

declare const both: A & B
both.a
both.b

| 观察角度 | A | B | A & B | | --- | --- | --- | | 可接受的值 | 满足 A 或 B | 同时满足 A 和 B | | 直接保证的成员 | 共有安全成员 | 双方全部成员 | | 常用建模 | 多状态、多个输入形态 | 能力组合、增强对象 | | 主要风险 | 未收窄访问特有成员 | 冲突属性变为 never |

若用 loadingdata?error? 三个独立字段建模,布尔和可选组合会产生多种无效状态;改成 3 个判别联合成员,实际只允许加载、成功、失败这 3 种合法状态。联合类型的价值不只是少写字段,而是让不可能状态无法构造。

记忆钩子:联合扩大“值的入口”却缩小“直接可用能力”,交叉缩小“值的入口”却汇集“可用能力”。

七、常见误区与追问

  • 误区:A | B 类型的值同时拥有 A 和 B 的所有属性。 运行时只保证它属于至少一个成员,未收窄前只能使用所有成员都安全的能力。
  • 误区:A & B 会在运行时自动合并两个对象。 它只描述静态约束,真正创建合并值仍需执行对象组合逻辑。
  • 误区:交叉类型出现 never 一定是编译器故障。 不兼容同名属性要求一个值同时满足互斥类型,自然会得到不可能的 never。
  • 追问:为什么判别联合优于多个可选字段? 每个成员把字段依赖绑定在同一状态中,减少无效组合并支持准确收窄。
  • 追问:联合类型如何做穷尽检查? 在 switch 的 default 分支把剩余值赋给 never,新增成员未处理时编译器会报错。
  • 追问:交叉对象与对象展开的冲突规则相同吗? 不相同;交叉要求类型同时成立,对象展开在运行时通常由后写属性覆盖前写属性。
  • 追问:string 与 number 的交叉是什么? 两者没有共同的实际值,结果是 never。

八、加强记忆

联合类型是“可能是这个或那个”,交叉类型是“必须既有这个又有那个”。联合要收窄,交叉要注意属性冲突。

从可能值集合判断入口大小,再从安全成员判断可用能力,就不会被“或/且”的表面文字绕晕。