第8章:类型系统进阶
类型保护与类型收缩
概述
类型保护(Type Guards)和类型收缩(Type Narrowing)是 TypeScript 中用于在特定代码块内缩小变量类型范围的重要机制。它们通过条件判断或特定语法,帮助编译器推断更精确的类型,从而增强类型安全性并减少运行时错误。
1. 常见的类型保护方式
(1) typeof 类型保护
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // 此处 value 被推断为 string
} else {
console.log(value.toFixed(2)); // 此处 value 被推断为 number
}
}
(2) instanceof 类型保护
class Animal { move() {} }
class Bird extends Animal { fly() {} }
function handleAnimal(animal: Animal) {
if (animal instanceof Bird) {
animal.fly(); // 此处 animal 被推断为 Bird
}
}
(3) 自定义类型谓词(User-Defined Type Guards)
interface Cat { meow(): void }
interface Dog { bark(): void }
function isCat(pet: Cat | Dog): pet is Cat {
return (pet as Cat).meow !== undefined;
}
function petSound(pet: Cat | Dog) {
if (isCat(pet)) {
pet.meow(); // 类型被收缩为 Cat
}
}
2. 类型收缩的典型场景
(1) 真值收缩(Truthiness Narrowing)
function processValue(value?: string) {
if (value) {
console.log(value.trim()); // value 被收缩为 string(排除 null/undefined/"")
}
}
(2) 相等性收缩(Equality Narrowing)
function example(x: string | number, y: string | boolean) {
if (x === y) {
// 此处 x 和 y 都被收缩为 string
}
}
(3) in 操作符收缩
interface Admin { role: string }
interface User { email: string }
function redirect(entity: Admin | User) {
if ("role" in entity) {
console.log("Admin:", entity.role); // 收缩为 Admin
}
}
3. 判别式联合(Discriminated Unions)
通过共享字面量属性(判别式)实现精确类型收缩:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number };
function getArea(shape: Shape) {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2; // 精确识别为 circle 类型
case "square":
return shape.side ** 2;
}
}
4. 注意事项
- 类型断言 vs 类型保护
避免过度使用as断言,优先让类型保护自动推断。 - 复杂联合类型
当处理多层嵌套的联合类型时,可能需要组合多种保护方式。 - 性能影响
过多的类型保护可能增加编译时间,但不会影响运行时性能。
示例:综合应用
function processInput(input: unknown) {
if (typeof input === "string") {
console.log(input.toUpperCase());
} else if (Array.isArray(input)) {
console.log(input.length);
} else if (input && typeof input === "object" && "id" in input) {
console.log((input as { id: string }).id);
}
}
通过合理使用类型保护与收缩,可以显著提升代码的类型安全性和可维护性。
