交叉类型(Intersection Types)和联合类型(Union Types)是 TypeScript 中用于创建复杂类型的两种重要工具。它们有助于更灵活地定义类型,但有着不同的语义和用途。

交叉类型(Intersection Types)

定义: 交叉类型 A & B 表示一个类型,它同时具有类型 A 和类型 B 的所有属性。

用途: 交叉类型用于合并多个类型的属性。它创建的是一个新类型,这个新类型要求同时满足所有合并的类型约束。

示例:

type A = { name: string };
type B = { age: number };
type Person = A & B;
 
const john: Person = {
    name: "John",
    age: 30
    // 必须同时包含 name 和 age 属性
};

在上面的例子中,Person 类型同时具备 AB 类型的所有属性,因此 john 变量必须同时有 nameage 属性。

联合类型(Union Types)

定义: 联合类型 A | B 表示一个类型,它可以是 A 类型,也可以是 B 类型,但不同时具有这两种类型的所有属性。

用途: 联合类型用于创建能够持有多种不同类型中的一种的变量。这在函数参数、变量和返回值类型需要多态性时非常有用。

示例:

type A = { name: string };
type B = { age: number };
type Either = A | B;
 
const alice: Either = { name: "Alice" };  // 有效
const bob: Either = { age: 25 };          // 有效
const charlie: Either = { name: "Charlie", age: 40 }; // 也有效,因为它满足 A 和 B 的其中之一

在上面的例子中,alicebob 变量可以是 A 类型或 B 类型中的任意一种。charlie 变量同时具备 AB 类型的属性,因此它满足 Either 类型的要求。

区别与使用场景

特点交叉类型联合类型
定义同时具有所有类型的属性具有多种类型中的一种
语法A & BA | B
示例{ a: string } & { b: number } = { a: "hi", b: 10 }{ a: string } | { b: number } = { a: "hi" } or { b: 10 }
使用场景合并多个对象的属性允许变量是多种类型之一
检查属性同时具备所有交叉的属性可以具有单独一种类型属性,但不能混合所有属性

实际应用

交叉类型的应用场景

  1. 增强类型: 你可以将多种类型的属性组合成一个更强大的类型。

    type Drawable = { draw: () => void };
    type Erasable = { erase: () => void };
    type DrawingTool = Drawable & Erasable;
     
    const tool: DrawingTool = {
      draw: () => console.log("Drawing"),
      erase: () => console.log("Erasing")
    };
  2. 混合多个接口或类型:

    interface Point { x: number; y: number; }
    interface Colored { color: string; }
    type ColoredPoint = Point & Colored;
     
    const coloredPoint: ColoredPoint = { x: 0, y: 0, color: "red" };

联合类型的应用场景

  1. 多态函数参数: 允许函数参数接受多种类型。

    function printId(id: string | number) {
      console.log("Your ID is: " + id);
    }
     
    printId(101);   // 有效
    printId("202"); // 也有效
  2. 类型别名: 用于函数返回多种类型中的一种。

    type Success = { status: "success"; data: unknown };
    type Error = { status: "error"; message: string };
    type Response = Success | Error;
     
    function handleResponse(response: Response) {
      if (response.status === "success") {
        console.log("Data: " + response.data);
      } else {
        console.log("Error: " + response.message);
      }
    }

总结来说,交叉类型用于创建一个包含所有类型属性的组合类型,而联合类型则用于定义一个可以是多种类型中的某一个的类型。根据具体应用需求选择适合的类型,以实现更强大的类型系统。