类型守卫是typescript运行时类型缩小的核心手段,通过typeof识别原始类型、instanceof确认类实例,并可组合使用以安全处理联合类型,避免用类型断言替代。

类型守卫是 TypeScript 实现运行时类型缩小的核心手段——它让编译器在 if、else 或 switch 分支中,根据真实执行的判断逻辑,把联合类型(如 string | number | Error)逐步“收窄”为当前分支里唯一可能的具体类型,从而允许安全调用该类型的专属属性或方法。
typeof 守卫:识别原始类型最直接的方式
适用于 string、number、boolean、bigint、symbol、undefined 和 function 这些 JavaScript 原始类型(注意:typeof null === "object",不是原始类型)。
- 写法必须严格为 typeof 变量 === "string"(双等号、字符串字面量全小写),其他形式如
==、!==或typeof x == "string"不会触发类型缩小 - 对联合类型
string | number | boolean,每个typeof分支都能获得唯一子类型,可直接调用.toUpperCase()、.toFixed()、? "true" : "false" -
typeof x === "object"不能等同于“x 是对象实例”,因为 null 也满足该条件;需配合x !== null才能安全进入对象处理分支
instanceof 守卫:确认类实例身份的关键检查
用于判断一个值是否是某个类(或构造函数)的实例,依赖运行时原型链,只对通过 class 或 function 构造出来的对象有效。
- 语法是 变量 instanceof 类名,例如
err instanceof CustomError或date instanceof Date - 支持继承:若
Dog extends Animal,则dog instanceof Animal为 true,且分支内dog类型会缩小为Animal;想保留Dog类型,就得用instanceof Dog - 慎用于内置对象:虽然
arr instanceof Array语法合法,但跨 iframe 时可能失效,推荐改用Array.isArray(arr)
组合使用:应对混合类型的实际场景
真实参数往往既含原始值又含自定义类实例,比如函数入参可能是 string | number | ApiError。这时单靠一种守卫不够,需要分层判断。
- 先用
typeof排除所有原始类型,再用instanceof处理剩余对象分支 - 顺序很重要:把最具体、最易排除的守卫放前面,避免遗漏;TypeScript 按 if-else 链顺序逐级缩小,确保每个分支类型唯一
- 示例:处理错误参数
error: string | number | ApiError,应写成:if (typeof error === "string") { ... }<br> else if (typeof error === "number") { ... }<br> else if (error instanceof ApiError) { ... }
避免常见误区:守卫 ≠ 类型断言
类型守卫是运行时检查 + 编译时推导,具备安全性;而类型断言(如 value as string)只是告诉编译器“信我”,不校验实际值,容易埋下隐患。
- 不要用断言替代守卫:比如
(item as string).length能过编译,但若 item 实际是 number,运行时就报错 - 守卫必须可被静态识别:条件表达式要简单明确,避免嵌套函数调用或复杂计算,否则编译器无法推导缩小结果
- 注意真值检查的局限性:仅靠
if (val)只能排除null和undefined,不能区分string和number,仍需后续守卫










