ZetCode

TypeScript 类型保护

最后修改时间:2025年3月3日

TypeScript 中的类型保护是用于在特定代码块中缩小变量类型的技术。它们通过允许基于运行时检查的条件逻辑来确保类型安全。本教程将通过实际示例探讨类型保护。

类型保护是执行运行时检查以确定变量类型的表达式。它们有助于 TypeScript 在代码块中推断出更具体的类型。常见的类型保护包括 typeofinstanceof 和自定义类型谓词。

使用 typeof

typeof 运算符用于检查字符串、数字和布尔值等原始值的类型。

typeof_guard.ts
function printValue(value: string | number): void {
    if (typeof value === "string") {
        console.log(`String: ${value}`);
    } else {
        console.log(`Number: ${value}`);
    }
}

printValue("Hello");  // Output: String: Hello
printValue(42);       // Output: Number: 42

使用 instanceof

instanceof 运算符用于检查一个对象是否是特定类的实例。

instanceof_guard.ts
class Dog {
    bark(): void {
        console.log("Woof!");
    }
}

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

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

handleAnimal(new Dog());  // Output: Woof!
handleAnimal(new Cat());  // Output: Meow!

自定义类型谓词

自定义类型谓词允许定义自己的类型保护函数。它们返回一个布尔值并使用 is 关键字。

custom_predicate.ts
interface Bird {
    fly(): void;
}

interface Fish {
    swim(): void;
}

function isBird(animal: Bird | Fish): animal is Bird {
    return (animal as Bird).fly !== undefined;
}

function handleAnimal(animal: Bird | Fish): void {
    if (isBird(animal)) {
        animal.fly();
    } else {
        animal.swim();
    }
}

handleAnimal({ fly: () => console.log("Flying!") });  // Output: Flying!
handleAnimal({ swim: () => console.log("Swimming!") });  // Output: Swimming!

使用 in 运算符

in 运算符用于检查一个属性是否存在于一个对象中。

in_operator.ts
interface Car {
    drive(): void;
}

interface Boat {
    sail(): void;
}

function handleVehicle(vehicle: Car | Boat): void {
    if ("drive" in vehicle) {
        vehicle.drive();
    } else {
        vehicle.sail();
    }
}

handleVehicle({ drive: () => console.log("Driving!") });  // Output: Driving!
handleVehicle({ sail: () => console.log("Sailing!") });  // Output: Sailing!

带字面量的联合类型

类型保护可以缩小带有字面量值的联合类型。

literal_guard.ts
type Status = "success" | "error";

function handleStatus(status: Status): void {
    if (status === "success") {
        console.log("Operation succeeded!");
    } else {
        console.log("Operation failed!");
    }
}

handleStatus("success");  // Output: Operation succeeded!
handleStatus("error");    // Output: Operation failed!

Null 检查

类型保护可以通过检查 nullundefined 来处理可空类型。

null_check.ts
function printLength(value: string | null): void {
    if (value === null) {
        console.log("Value is null");
    } else {
        console.log(`Length: ${value.length}`);
    }
}

printLength(null);        // Output: Value is null
printLength("Hello");     // Output: Length: 5

数组的类型保护

类型保护可以缩小数组中的类型。

array_guard.ts
function processArray(arr: (string | number)[]): void {
    arr.forEach(item => {
        if (typeof item === "string") {
            console.log(`String: ${item}`);
        } else {
            console.log(`Number: ${item}`);
        }
    });
}

processArray(["apple", 42, "banana", 100]);  // Output: String: apple, Number: 42, String: banana, Number: 100

对象的类型保护

类型保护可以根据对象的属性来区分不同的对象类型。

object_guard.ts
interface Square {
    size: number;
}

interface Circle {
    radius: number;
}

function calculateArea(shape: Square | Circle): number {
    if ("size" in shape) {
        return shape.size * shape.size;
    } else {
        return Math.PI * shape.radius * shape.radius;
    }
}

console.log(calculateArea({ size: 5 }));          // Output: 25
console.log(calculateArea({ radius: 3 }));        // Output: 28.274333882308138

类的类型保护

类型保护可以区分不同的类实例。

class_guard.ts
class Rectangle {
    constructor(public width: number, public height: number) {}
}

class Triangle {
    constructor(public base: number, public height: number) {}
}

function calculateArea(shape: Rectangle | Triangle): number {
    if (shape instanceof Rectangle) {
        return shape.width * shape.height;
    } else {
        return (shape.base * shape.height) / 2;
    }
}

console.log(calculateArea(new Rectangle(4, 5)));  // Output: 20
console.log(calculateArea(new Triangle(3, 6)));   // Output: 9

组合类型保护

多个类型保护可以组合起来用于复杂的类型缩小。

combined_guards.ts
function processValue(value: string | number | boolean): void {
    if (typeof value === "string") {
        console.log(`String: ${value}`);
    } else if (typeof value === "number") {
        console.log(`Number: ${value}`);
    } else {
        console.log(`Boolean: ${value}`);
    }
}

processValue("Hello");  // Output: String: Hello
processValue(42);       // Output: Number: 42
processValue(true);     // Output: Boolean: true

最佳实践

来源

从类型创建类型

本教程介绍了 TypeScript 类型保护及其实用示例。使用这些技术可以编写更安全、更易于维护的代码。

作者

我的名字是 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 TypeScript 教程