TypeScript 类型保护
最后修改时间:2025年3月3日
TypeScript 中的类型保护是用于在特定代码块中缩小变量类型的技术。它们通过允许基于运行时检查的条件逻辑来确保类型安全。本教程将通过实际示例探讨类型保护。
类型保护是执行运行时检查以确定变量类型的表达式。它们有助于 TypeScript 在代码块中推断出更具体的类型。常见的类型保护包括 typeof、instanceof 和自定义类型谓词。
使用 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 检查
类型保护可以通过检查 null 或 undefined 来处理可空类型。
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
最佳实践
- 尽早使用类型保护: 尽快缩小类型。
- 组合保护: 将多个保护用于复杂逻辑。
- 利用自定义谓词: 创建可重用的类型保护。
- 处理边界情况: 考虑
null和undefined。 - 保持保护简洁: 避免过于复杂的类型保护。
来源
本教程介绍了 TypeScript 类型保护及其实用示例。使用这些技术可以编写更安全、更易于维护的代码。