TypeScript 类型收窄:那些让类型「活起来」的写法
什么叫收窄
一个变量声明成联合类型后,TypeScript 会随着你写的判断,逐步缩小它的可能类型。
type Result = { ok: true; data: string } | { ok: false; error: Error };
function handle(r: Result) {
if (r.ok) {
r.data; // 这里 TS 知道是成功分支
} else {
r.error; // 这里是失败分支
}
}
这个 ok: true / ok: false 就叫可辨识联合,是最推荐的做法。
常见收窄手段
| 手段 | 例子 |
|---|---|
| typeof | typeof x === 'string' |
| instanceof | x instanceof Date |
| in | 'name' in obj |
| 相等判断 | x === 'success' |
| 自定义守卫 | function isUser(v: unknown): v is User |
自定义类型守卫
当内置手段不够用时:
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
typeof (value as User).id === 'number'
);
}
注意返回类型写的是 value is User,不是 boolean。写错这点守卫就完全失效。
踩过的坑
坑一:解构后丢失收窄
function f(r: Result) {
const { ok } = r;
if (ok) {
r.data; // 报错,收窄没跟着走
}
}
对策:判断用原始变量,别解构。
坑二:闭包里失效
因为在回调执行时,外部变量可能已经变了。对策是把收窄后的值赋给新的 const。
小结
类型收窄是 TS 里投入产出比最高的知识之一。学明白之后,你会开始依赖类型检查,而不是绕过它。