联合类型和交叉类型的区别是什么?
介绍 TypeScript 中的联合类型和交叉类型的定义、语法及其核心行为差异,并探讨它们在实际开发中的应用场景。
联合类型(Union Types)和交叉类型(Intersection Types)在 TypeScript 中都是高级类型工具,但存在本质差异,主要体现为:
- 定义和语法
- 联合类型:通过
|
运算符定义,表示一个值可以是多种类型中的某一种。示例:type StringOrNumber = string | number; // 变量可接受 string 或 number
- 交叉类型:通过
&
运算符定义,表示一个值必须同时满足多个类型的所有特性,将多个类型合并为一个新类型。示例:interface Point { x: number; } interface Color { color: string; } type PositionedColor = Point & Color; // 对象同时具有 x 和 color 属性
- 联合类型:通过
- 核心行为差异
- 逻辑关系:
- 联合类型:是“或”(OR)关系。例如,
let id: string | number
意指id
可能取自字符串型或数值型,但同一时刻只能属于其一。 - 交叉类型:是“与”(AND)关系。例如,
let pet: Dog & Cat
对象需具备Dog
类型中的bark
方法和Cat
类型中的meow
方法。
- 联合类型:是“或”(OR)关系。例如,
- 基础类型处理:
- 联合类型如
type A = string | number
表示值可为任一类型。 - 交叉类型如
type B = string & number
结果为never
(因为无值同时是两者).
- 联合类型如
- 对象属性:
- 在联合类型对象中,访问属性时必须使用类型守卫,因为在未明确类型时只能访问公共属性. 示例:
type Entity = { id: number } | { username: string }; let ent: Entity = { id: 123 }; if ('id' in ent) console.log(ent.id); // 需要使用守卫安全访问
- 在交叉类型对象中,所有成员属性直接兼容和扩展,无此限制.
- 在联合类型对象中,访问属性时必须使用类型守卫,因为在未明确类型时只能访问公共属性. 示例:
- 逻辑关系:
- 实际应用场景
- 联合类型适用:常用于处理可空值(如
response: Data | null
)、函数参数的多态处理(如处理不同输入类型)。需配合typeof
或 in 运算符做类型分支检查. - 交叉类型适用:用于合并多个接口以避免复杂继承层次(如
CombinedType = Type1 & Type2
),或对象增强设计.
- 联合类型适用:常用于处理可空值(如
- 注意事项
- 属性冲突:交叉类型中,如果多个类型有同名属性但类型不同(如
{ age: number } & { age: string }
),会导致属性成为never
从而需显式处理. - 工具辅助:TypeScript 条件类型(如
extends
)可利用二者构建复杂的类型系统。
- 属性冲突:交叉类型中,如果多个类型有同名属性但类型不同(如