第五节 类型系统进阶-类型守卫(Type Guard)的实现方式
一、基础操作符守卫
1. typeof
守卫
用于原始类型(string
/number
/boolean
等)的运行时检查:
function process(input: string | number) {if (typeof input === "string") {console.log(input.toUpperCase()); // ✅ 类型收窄为 string} else {console.log(input.toFixed(2)); // ✅ 类型收窄为 number}
}
限制:
- 对对象类型统一返回
"object"
,无法区分具体结构。
2. instanceof
守卫
针对类实例的类型判断:
class Car { drive() {} }
class Bike { ride() {} }function move(vehicle: Car | Bike) {if (vehicle instanceof Car) {vehicle.drive(); // ✅ 类型收窄为 Car} else {vehicle.ride(); // ✅ 类型收窄为 Bike}
}
适用场景:面向对象编程中的类实例区分。
🛠️ 二、自定义类型守卫函数
通过 类型谓词(value is Type
)主动声明类型收窄逻辑:
// 判断是否为字符串数组
function isStringArray(arr: unknown[]): arr is string[] {return arr.every(item => typeof item === "string");
}function handle(arr: unknown[]) {if (isStringArray(arr)) {arr.join(","); // ✅ 类型收窄为 string[]}
}
优势:
- 可复用验证逻辑(如 API 响应数据校验);
- 结合第三方库(如 Zod)实现运行时验证 + 类型安全:
import { z } from "zod"; const EmailSchema = z.string().email();function isValidEmail(email: string): email is Email {return EmailSchema.safeParse(email).success; // Zod 验证 + 类型谓词 }
🔑 三、索引类型与属性检查
1. keyof
约束
确保属性名存在于对象中:
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {return obj[key]; // ✅ key 被限定为 T 的合法属性
}
2. in
操作符守卫
通过属性存在性区分对象类型:
interface Dog { bark(): void }
interface Cat { meow(): void }function sound(animal: Dog | Cat) {if ("bark" in animal) {animal.bark(); // ✅ 类型收窄为 Dog} else {animal.meow(); // ✅ 类型收窄为 Cat}
}
⚙️ 四、条件类型与分发特性
1. 条件类型(T extends U ? X : Y
)
在类型别名中实现静态类型分支:
type IsNumber<T> = T extends number ? true : false;
type A = IsNumber<5>; // true
type B = IsNumber<"hello">; // false
2. 分布式条件类型
联合类型被拆分处理:
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>; // string[] | number[]
🧩 五、枚举守卫与映射
处理枚举类型时需注意 类型收窄为 never
的问题:
enum BackendGender { MALE, FEMALE }
enum FrontendGender { MALE, FEMALE }function mapGender(gender: BackendGender): FrontendGender {// 直接比较可能导致类型冲突if (gender === BackendGender.MALE) {return FrontendGender.MALE; // ✅ 安全映射}// ...
}
替代方案:使用泛型映射函数避免 never
。
💡 六、工程实践建议
- 优先内置守卫:简单场景用
typeof
/instanceof
/in
。 - 复杂逻辑封装:自定义守卫函数提升复用性(如数据验证层)。
- 结合工具类型:
Partial<T>
:部分属性可选化;Required<T>
:所有属性必填;Pick<T, K>
:提取指定属性。
- 避免
any
:用unknown
+ 类型守卫替代危险操作。
// 安全解析未知数据
function parseResponse(data: unknown): User {if (isUser(data)) { // 自定义守卫return data;}throw new Error("Invalid data");
}
💡 核心价值:类型守卫通过 编译时类型收窄 和 运行时验证 的结合,在动态语言特性与静态类型安全之间架起桥梁,显著提升代码健壮性。
通过灵活组合这些技术,可高效处理 API 响应、用户输入、状态管理等场景的类型不确定性,减少 undefined is not a function
等运行时错误。