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); // 1232. 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)的功能,但更轻量。