如何编写可识别多种类型的TypeScript类型守卫?
TypeScript 实现多类型的类型收窄方案
你想要实现的是能针对联合类型中每个具体子类型做精准类型判断的功能,TypeScript里没法用单个函数直接返回“动态类型守卫”,但可以通过以下几种实用方式达成需求:
1. 为每个子类型单独编写类型守卫函数
如果你的类型是类(可通过instanceof判断),可以为每个类型单独写类型守卫,TypeScript会通过类型谓词(animal is Cat)关联返回值与参数类型:
先定义类:
class Cat { meow() {} } class Dog { bark() {} } class Bird { chirp() {} } class Fish { swim() {} } type Animal = Cat | Dog | Bird | Fish;
编写单个类型守卫:
function isCat(animal: Animal): animal is Cat { return animal instanceof Cat; } function isDog(animal: Animal): animal is Dog { return animal instanceof Dog; } function isBird(animal: Animal): animal is Bird { return animal instanceof Bird; } function isFish(animal: Animal): animal is Fish { return animal instanceof Fish; }
使用时,TypeScript会自动收窄类型:
function handleAnimal(animal: Animal) { if (isCat(animal)) { animal.meow(); // 类型已收窄为Cat } else if (isDog(animal)) { animal.bark(); // 类型已收窄为Dog } else if (isBird(animal)) { animal.chirp(); } else { animal.swim(); // 剩余类型自动推断为Fish } }
2. 利用判别式联合类型(最简洁方案)
如果你的类型是接口/字面量类型,或者可以给类添加标识属性,推荐使用判别式联合类型。通过给每个类型添加一个唯一的字面量属性,TypeScript会自动根据该属性完成类型收窄:
接口/字面量类型示例:
type Cat = { type: 'cat'; meow: () => void }; type Dog = { type: 'dog'; bark: () => void }; type Bird = { type: 'bird'; chirp: () => void }; type Fish = { type: 'fish'; swim: () => void }; type Animal = Cat | Dog | Bird | Fish; function handleAnimal(animal: Animal) { switch (animal.type) { case 'cat': animal.meow(); break; case 'dog': animal.bark(); break; case 'bird': animal.chirp(); break; case 'fish': animal.swim(); break; } }
类类型添加判别式示例:
class Cat { readonly type = 'cat' as const; meow() {} } class Dog { readonly type = 'dog' as const; bark() {} } // 其他类同理添加type属性 type Animal = Cat | Dog | Bird | Fish; function handleAnimal(animal: Animal) { switch (animal.type) { case 'cat': animal.meow(); break; case 'dog': animal.bark(); break; // ...其他分支 } }
3. 通用泛型类型守卫函数
如果想要一个通用的检查函数,可以结合泛型与类构造函数实现,需要传入目标类型的构造器:
type Animal = Cat | Dog | Bird | Fish; function isAnimalType<T extends typeof Cat | typeof Dog | typeof Bird | typeof Fish>( animal: Animal, targetType: T ): animal is InstanceType<T> { return animal instanceof targetType; }
使用时:
const animal: Animal = getAnimal(); if (isAnimalType(animal, Cat)) { animal.meow(); // 类型收窄为Cat }
注意:你原来代码中的return is Cat是错误语法,类型守卫函数必须返回布尔值,TypeScript通过animal is 目标类型这种类型谓词来完成类型关联。
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

