类型保护是TypeScript用于在条件分支中缩小变量类型范围的机制,通过特定的语法结构让编译器能够推导出更精确的类型信息。其核心价值在于提升代码类型安全性,同时保持开发效率。
1. 类型谓词(Type Predicates)
interface Cat { purr(): void; }
interface Dog { bark(): void; }
function isCat(animal: Cat | Dog): animal is Cat {
return 'purr' in animal;
}
function handleAnimal(animal: Cat | Dog) {
if (isCat(animal)) {
animal.purr(); // 自动识别Cat类型
} else {
animal.bark(); // 自动推导为Dog类型
}
}
最佳实践建议:
in
操作符进行属性存在性检查2. typeof类型保护
function process(input: string | number) {
if (typeof input === 'string') {
console.log(input.toUpperCase()); // 自动推导string类型
} else {
console.log(input.toFixed(2)); // 推导number类型
}
}
注意事项:
3. instanceof类型保护
class Car { drive() {} }
class Truck { load() {} }
function operate(vehicle: Car | Truck) {
if (vehicle instanceof Car) {
vehicle.drive();
} else {
vehicle.load();
}
}
适用场景:
4. 字面量类型保护
type Status = 'loading' | 'success' | 'error';
function handleStatus(status: Status) {
if (status === 'loading') {
showSpinner();
} else if (status === 'success') {
showData();
} else {
showError();
}
}
优化技巧:
5. in操作符保护
interface Admin { permissions: string[]; }
interface User { email: string; }
function authorize(person: Admin | User) {
if ('permissions' in person) {
logAccess(person.permissions); // Admin类型
} else {
sendEmail(person.email); // User类型
}
}
优势分析:
复合类型守卫
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(item => typeof item === 'string');
}
function handleArray(input: unknown) {
if (isStringArray(input)) {
// 安全访问字符串数组方法
const uppercased = input.map(s => s.toUpperCase());
}
}
异步类型守卫
async function fetchIsAdmin(userId: string): Promise {
const response = await fetch(`/api/auth/${userId}`);
const data = await response.json();
return data.role === 'admin';
}
async function handleUser(userId: string) {
if (await fetchIsAdmin(userId)) {
// 显示管理员面板
}
}
// 错误示例:未正确实现类型谓词
function isCatBroken(animal: Cat | Dog): boolean {
return 'purr' in animal; // 缺少类型谓词声明
}
// 正确用法
function isCat(animal: Cat | Dog): animal is Cat {
return 'purr' in animal;
}
type Shape = Circle | Square;
// 错误:未处理全部类型分支
function getArea(shape: Shape) {
if ('radius' in shape) {
return Math.PI * shape.radius ** 2;
}
// 缺少Square处理逻辑
}
// 正确做法:使用穷尽检查
function getAreaSafe(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'square':
return shape.size ** 2;
default:
const _exhaustiveCheck: never = shape;
return _exhaustiveCheck;
}
}
class Base { id: number = 0; }
class Derived extends Base { extra: string = ''; }
function checkType(obj: Base) {
// 可能错误判断继承对象
if ('extra' in obj) {
// 实际上可能来自其他子类
}
}
创建可复用的高级类型守卫:
type Constructor = new (...args: any[]) => T;
function isInstanceOf(obj: any, klass: Constructor): obj is T {
return obj instanceof klass;
}
// 使用示例
if (isInstanceOf(target, HTMLElement)) {
target.classList.add('active');
}
通过合理运用类型保护机制,开发者可以在保持TypeScript类型安全优势的同时,显著提升代码可维护性和开发效率。重点在于根据具体场景选择最合适的保护策略,并建立规范的类型守卫使用模式。