Skip to content

TypeScript 联合类型

联合类型(Union Types)是 TypeScript 中一个强大的特性,它允许一个变量可以是多种类型之一。我们使用竖线(|)来分隔每种类型。

什么是联合类型?

当你希望一个变量、函数参数或对象属性可以接受不同类型的值时,联合类型就非常有用。

基础示例

typescript
let value: string | number;

value = "Hello, TypeScript"; // OK
value = 123;                 // OK

// value = true; // Error: Type 'boolean' is not assignable to type 'string | number'.

这个例子中,value 变量既可以是一个 string,也可以是一个 number

使用联合类型

当一个值的类型是联合类型时,我们只能访问这个联合类型中所有类型都共有的成员。

typescript
interface Bird {
    fly(): void;
    layEggs(): void;
}

interface Fish {
    swim(): void;
    layEggs(): void;
}

function getSmallPet(): Fish | Bird {
    // ...返回一个 Fish 或 Bird 实例
    return { fly: () => {}, layEggs: () => {} };
}

let pet = getSmallPet();

// 我们可以调用 layEggs(),因为它是 Fish 和 Bird 的共有方法
pet.layEggs();

// 但我们不能直接调用 fly() 或 swim(),因为 TypeScript 不确定 pet 到底是哪种类型
// pet.fly(); // Error: Property 'fly' does not exist on type 'Fish | Bird'.

类型收窄 (Type Narrowing)

为了能够使用特定类型的方法或属性,我们需要告诉 TypeScript 当前变量的具体类型。这个过程称为“类型收窄”或“类型守卫”(Type Guards)。

有多种方法可以实现类型收窄:

1. typeof 类型守卫

对于基本类型,typeof 是最常见的类型守卫。

typescript
function printId(id: number | string) {
    if (typeof id === "string") {
        // 在这个代码块中,TypeScript 知道 id 是 string 类型
        console.log(id.toUpperCase());
    } else {
        // 在这里,id 必定是 number 类型
        console.log(id);
    }
}

printId("abc"); // ABC
printId(123); // 123

2. instanceof 类型守卫

instanceof 用于检查一个实例是否属于某个类。

typescript
class Dog { bark() { console.log("Woof!"); } }
class Cat { meow() { console.log("Meow!"); } }

function makeSound(animal: Dog | Cat) {
    if (animal instanceof Dog) {
        // TypeScript 知道 animal 是 Dog 类型
        animal.bark();
    } else {
        // TypeScript 知道 animal 是 Cat 类型
        animal.meow();
    }
}

3. in 操作符类型守卫

in 操作符可以检查一个对象是否拥有某个属性。

typescript
interface Bird {
    fly(): void;
    layEggs(): void;
}

interface Fish {
    swim(): void;
    layEggs(): void;
}

function move(animal: Bird | Fish) {
    if ("fly" in animal) {
        // TypeScript 知道 animal 是 Bird 类型
        return animal.fly();
    }
    // TypeScript 知道 animal 是 Fish 类型
    return animal.swim();
}

字面量联合类型

联合类型不仅可以用于类型,还可以用于具体的字面量值。这可以用来限制一个变量只能取几个特定的字符串或数字值。

typescript
type Alignment = "left" | "right" | "center";

let textAlign: Alignment;

textAlign = "center"; // OK
textAlign = "left";   // OK
// textAlign = "justify"; // Error: Type '"justify"' is not assignable to type 'Alignment'.


function setMargin(margin: 0 | 10 | 20) {
    // ...
}

setMargin(10); // OK
// setMargin(5); // Error: Argument of type '5' is not assignable to parameter of type '0 | 10 | 20'.

这种模式在 API 设计中非常有用,可以提供类似枚举(Enum)的功能,但更轻量。

本站内容仅供学习和研究使用。