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

介绍 TypeScript 中的联合类型和交叉类型的定义、语法及其核心行为差异,并探讨它们在实际开发中的应用场景。

TypeScript 中等 高级类型 基础 联合类型

联合类型(Union Types)和交叉类型(Intersection Types)在 TypeScript 中都是高级类型工具,但存在本质差异,主要体现为:

  1. 定义和语法
    • 联合类型:通过 | 运算符定义,表示一个值可以是多种类型中的某一种。示例:
      type StringOrNumber = string | number; // 变量可接受 string 或 number
      
    • 交叉类型:通过 & 运算符定义,表示一个值必须同时满足多个类型的所有特性,将多个类型合并为一个新类型。示例:
      interface Point { x: number; }
      interface Color { color: string; }
      type PositionedColor = Point & Color; // 对象同时具有 x 和 color 属性
      
  2. 核心行为差异
    • 逻辑关系
      • 联合类型:是“或”(OR)关系。例如,let id: string | number 意指 id 可能取自字符串型或数值型,但同一时刻只能属于其一。
      • 交叉类型:是“与”(AND)关系。例如,let pet: Dog & Cat 对象需具备 Dog 类型中的 bark 方法和 Cat 类型中的 meow 方法。
    • 基础类型处理
      • 联合类型如 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); // 需要使用守卫安全访问
        
      • 在交叉类型对象中,所有成员属性直接兼容和扩展,无此限制.
  3. 实际应用场景
    • 联合类型适用:常用于处理可空值(如 response: Data | null)、函数参数的多态处理(如处理不同输入类型)。需配合 typeof 或 in 运算符做类型分支检查.
    • 交叉类型适用:用于合并多个接口以避免复杂继承层次(如 CombinedType = Type1 & Type2),或对象增强设计.
  4. 注意事项
    • 属性冲突:交叉类型中,如果多个类型有同名属性但类型不同(如 { age: number } & { age: string }),会导致属性成为 never 从而需显式处理.
    • 工具辅助:TypeScript 条件类型(如 extends)可利用二者构建复杂的类型系统。