自定义类型守卫的核心是声明形如 param is type 的返回类型,确保运行时判断能唯一区分目标类型,支持联合类型输入但仅收窄一个分支,泛型需通过约束绕过限制。

自定义类型守卫(用 value is Type 语法)的核心是:写一个返回布尔值的函数,同时让 TypeScript 编译器知道——当它返回 true 时,传入参数就**一定是某个更具体的类型**。
函数签名必须带类型谓词
关键不是逻辑本身,而是函数声明的写法。必须使用 parameterName is TargetType 这种形式作为返回类型:
- 不能写
boolean或any - 不能省略
is关键字和目标类型 - 参数名要和函数体内使用的变量名一致(否则类型收窄失效)
运行时判断要覆盖类型的本质特征
收窄是否可靠,取决于你检查的内容是否能**唯一区分目标类型**。例如:
- 对对象类型,优先检查
typeof obj === 'object'且非null,再验证关键属性存在且类型正确 - 对类实例,
instanceof最直接;对接口或无构造器的对象,用in操作符或属性存在性 + 类型检查组合 - 避免只靠属性名判断——比如
'id' in obj不够严谨,因为很多类型都有id;应加上typeof obj.id === 'number'等约束
支持联合类型输入,但守卫只作用于一个分支
函数参数类型通常是宽泛的联合类型(如 unknown、any 或 A | B | C),而守卫只负责确认其中一种可能:
- 例如
isUser(input: unknown): input is User—— 输入可能是任意值,但守卫只承诺:若返回true,那input就是User - 不需要覆盖所有分支,也不需要处理
false情况下的类型——那是 else 分支的事 - 多个守卫可叠加使用,比如先
isObject,再isUser,编译器会逐层收窄
注意泛型与守卫的配合边界
泛型参数本身不能直接用于类型谓词右侧(如 value is T 是非法的),但可以这样绕过:
- 把泛型约束到具体类型上,比如
<t extends id: number>(x: unknown): x is T</t> - 或者用类型守卫配合重载/条件类型,在调用侧实现类型推导,而非在守卫内部强行泛化
- 不要试图让一个守卫函数同时收窄多个不相关的泛型类型——拆成多个专用守卫更清晰安全











