跳到主要内容

TypeScript 类型保护

在 TypeScript 中,类型保护(Type Guards)是一种用于在运行时检查变量类型的技术。通过类型保护,我们可以在代码中缩小变量的类型范围,从而更安全地访问特定类型的属性和方法。本文将详细介绍 TypeScript 中的类型保护机制,并通过实际案例展示其应用场景。

什么是类型保护?

类型保护是一种在运行时检查变量类型的技术。它允许我们在代码中根据变量的类型执行不同的逻辑。TypeScript 提供了多种类型保护的方式,包括 typeofinstanceof、自定义类型保护函数等。

为什么需要类型保护?

在 TypeScript 中,变量的类型可能是联合类型(Union Types),例如 string | number。在这种情况下,我们无法直接访问特定类型的属性和方法,因为 TypeScript 无法确定变量的具体类型。通过类型保护,我们可以在运行时检查变量的类型,并缩小其类型范围,从而安全地访问特定类型的属性和方法。

类型保护的实现方式

1. typeof 类型保护

typeof 是 JavaScript 中的一个操作符,用于检查变量的类型。在 TypeScript 中,typeof 也可以用作类型保护。

typescript
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(`String value: ${value.toUpperCase()}`);
} else {
console.log(`Number value: ${value.toFixed(2)}`);
}
}

printValue("hello"); // 输出: String value: HELLO
printValue(3.14159); // 输出: Number value: 3.14

在上面的例子中,typeof 用于检查 value 的类型。如果 valuestring 类型,则调用 toUpperCase() 方法;如果 valuenumber 类型,则调用 toFixed() 方法。

2. instanceof 类型保护

instanceof 是 JavaScript 中的另一个操作符,用于检查对象是否是某个类的实例。在 TypeScript 中,instanceof 也可以用作类型保护。

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

class Cat {
meow() {
console.log("Meow!");
}
}

function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}

makeSound(new Dog()); // 输出: Woof!
makeSound(new Cat()); // 输出: Meow!

在上面的例子中,instanceof 用于检查 animal 的类型。如果 animalDog 类的实例,则调用 bark() 方法;如果 animalCat 类的实例,则调用 meow() 方法。

3. 自定义类型保护函数

除了 typeofinstanceof,我们还可以通过自定义类型保护函数来实现类型保护。自定义类型保护函数是一个返回布尔值的函数,其返回值类型为 value is Type,其中 Type 是我们希望检查的类型。

typescript
interface Bird {
fly(): void;
}

interface Fish {
swim(): void;
}

function isFish(pet: Bird | Fish): pet is Fish {
return (pet as Fish).swim !== undefined;
}

function move(pet: Bird | Fish) {
if (isFish(pet)) {
pet.swim();
} else {
pet.fly();
}
}

在上面的例子中,isFish 是一个自定义类型保护函数,用于检查 pet 是否是 Fish 类型。如果 isFish 返回 true,则 pet 的类型被缩小为 Fish,从而可以安全地调用 swim() 方法。

实际应用场景

场景 1:处理联合类型

在处理联合类型时,类型保护可以帮助我们安全地访问特定类型的属性和方法。

typescript
type Shape = Circle | Square;

interface Circle {
kind: "circle";
radius: number;
}

interface Square {
kind: "square";
sideLength: number;
}

function getArea(shape: Shape) {
if (shape.kind === "circle") {
return Math.PI * shape.radius ** 2;
} else {
return shape.sideLength ** 2;
}
}

在上面的例子中,shape.kind 是一个判别属性(Discriminant Property),用于区分 CircleSquare 类型。通过检查 shape.kind,我们可以安全地访问 CircleSquare 的特定属性。

场景 2:处理可选属性

在处理可选属性时,类型保护可以帮助我们避免访问未定义的属性。

typescript
interface User {
name: string;
age?: number;
}

function printUserInfo(user: User) {
console.log(`Name: ${user.name}`);
if (user.age !== undefined) {
console.log(`Age: ${user.age}`);
}
}

在上面的例子中,user.age 是一个可选属性。通过检查 user.age 是否为 undefined,我们可以避免访问未定义的属性。

总结

类型保护是 TypeScript 中一种强大的工具,用于在运行时检查变量的类型,并缩小其类型范围。通过 typeofinstanceof 和自定义类型保护函数,我们可以在代码中安全地访问特定类型的属性和方法,从而提高代码的类型安全性和可读性。

附加资源

练习

  1. 编写一个函数 printValue,接受一个 string | number 类型的参数,并根据参数的类型输出不同的结果。
  2. 创建一个自定义类型保护函数 isString,用于检查一个值是否为 string 类型,并在函数中使用该类型保护函数。
  3. 使用 instanceof 类型保护,编写一个函数 makeSound,接受 Dog | Cat 类型的参数,并根据参数的类型调用不同的方法。

通过完成这些练习,你将更好地理解 TypeScript 中的类型保护机制,并能够在实际项目中应用这些知识。