TypeScript 类型守卫完全指南
类型守卫把宽泛类型收窄为具体类型:typeof、instanceof、in、自定义谓词与可辨识联合。本文系统讲解全部守卫手段。
类型守卫 = 运行时检查 + 编译期收窄:typeof 管原始类型、instanceof 管类、in 管属性存在性、自定义谓词函数(x is T)管复杂结构、可辨识联合的判别字段管联合类型。守卫是 as 断言的安全替代。
内置守卫
function process(value: string | number | Date) {
if (typeof value === 'string') return value.toUpperCase();
if (typeof value === 'number') return value.toFixed(2);
if (value instanceof Date) return value.toISOString();
}
typeof 收窄原始类型;instanceof 收窄类实例;in 检查属性:
if ('breed' in animal) { animal.breed; } // Dog 分支
自定义类型谓词
function isUser(value: unknown): value is User {
return (
typeof value === 'object' && value !== null &&
'id' in value && 'name' in value
);
}
// 使用处自动收窄
if (isUser(data)) {
data.name; // User——运行时验证 + 编译期认可
}
value is User 是魔法签名:函数返回 true 时,TS 在调用处收窄类型。
可辨识联合(Discriminated Union)
type Result =
| { ok: true; data: User }
| { ok: false; error: string };
if (result.ok) {
result.data; // 自动收窄到成功分支
} else {
result.error; // 失败分支
}
共同的字面量判别字段(ok)让 switch/if 成为天然守卫——TS 中最优雅的建模模式之一。
空值守卫
// filter 收窄的经典技巧
const valid = list.filter((x): x is NonNullable<typeof x> => x != null);
// (现代 TS 对 filter(Boolean) 也有内置收窄)
常见问题(FAQ)
Q:类型谓词函数会撒谎吗?
会——实现写错(返回 true 但实际不符)类型系统信你。谓词函数的正确性靠测试保障,或用 Zod 等库生成。
Q:Array.isArray 为什么必要?
typeof [] 是 'object'——数组收窄必须用 Array.isArray(它有内置谓词签名)。
Q:asserts 谓词?
asserts value is T:函数不返回而是"断言通过或抛错"——输入校验函数的签名模式。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。