3. 什么叫类型谓词? is
约 1010 字大约 3 分钟
2025-06-08
一、简介
类型谓词一般指的是 is
类型谓词,用于执行类型检查,并缩小类型范围,避免运行时出现类型错误。它通过 value is Type
语法实现,通常结合一些特定逻辑,组成类型守卫(Type Guard)函数结合使用。
一般结合断言函数、类型守卫函数使用。断言函数就是一种类型守卫函数。
/**
* @desc 类型守卫函数 判断 value 是否为 TargetType 类型
* @param value 待判断类型的值
* @returns 布尔值,若为 true,则 value 被认定为 TargetType
*/
function isType(value: any): value is TargetType {
/* some code */
// return true / false;
}
value is TargetType
是一个类型断言,表示如果函数返回 true
,则 value
的类型会被收窄为 TargetType
。
二、使用场景
主要是用于参数属于复杂类型的哪一种。
1、区分联合类型
interface Cat {
meow(): void;
}
interface Dog {
bark(): void;
}
// 类型守卫函数 判断参数 animal 是否为 Cat 类型
function isCat(animal: Cat | Dog): animal is Cat {
return "meow" in animal; // 检查 animal 是否有 meow 方法
}
function handleAnimal(animal: Cat | Dog) {
// 使用类型守卫函数收窄类型范围
if (isCat(animal)) {
animal.meow(); // 类型收窄为 Cat
} else {
animal.bark(); // 类型收窄为 Dog
}
}
2、验证复杂对象结构
type User = { name: string; age: number };
type Admin = { name: string; privileges: string[] };
function isAdmin(user: User | Admin): user is Admin {
return "privileges" in user; // 检查 privileges 属性
}
const user: User | Admin = { name: "Alice", privileges: ["delete"] };
if (isAdmin(user)) {
console.log(user.privileges); // 类型收窄为 Admin
}
3、过滤数组类型
const mixedArray: (string | number)[] = ["a", 1, "b", 2];
// 使用类型谓词过滤字符串元素
const strings = mixedArray.filter(
(item): item is string => typeof item === "string"
);
// strings 类型被推断为 string[]
三、与普通类型守卫的区别
1、普通类型守卫(无 is
语法)
返回 boolean
的函数无法让 TypeScript 自动收窄类型。
interface Cat {
meow(): void;
}
interface Dog {
bark(): void;
}
const animal: Cat | Dog = { meow: () => console.log("meow") };
function isCatBoolean(animal: Cat | Dog): boolean {
return "meow" in animal;
}
if (isCatBoolean(animal)) {
animal.meow(); // 错误:TS 仍认为 animal 是 Cat | Dog
}
2、类型谓词(带 is
语法)
显式告诉编译器类型关系,触发类型收窄。
interface Cat {
meow(): void;
}
interface Dog {
bark(): void;
}
const animal: Cat | Dog = { meow: () => console.log("meow") };
function isCat(animal: Cat | Dog): animal is Cat {
return "meow" in animal;
}
if (isCat(animal)) {
animal.meow(); // 正确:类型收窄为 Cat
}
四、注意事项
1、逻辑必须与断言一致
如果函数返回 true
但实际类型不符,会导致运行时错误:
// 错误示例!逻辑与断言矛盾
function isString(value: any): value is string {
return typeof value === "number"; // 危险!
}
2、避免过度使用
简单场景优先使用内置类型守卫(如 typeof
、instanceof
)。
3、联合类型的唯一性
确保类型谓词能唯一区分联合类型中的成员:
interface A {
kind: "A";
}
interface B {
kind: "B";
}
function isA(obj: A | B): obj is A {
return obj.kind === "A"; // 通过字面量区分
}
五、常见面试问题
Q1:is
和 as
的区别?
is
用于类型谓词,是运行时检查 + 编译时类型收窄。as
类型断言,强制告诉编译器某个值的类型(无运行时检查,可能不安全)。
Q2:如何使用 Array.prototype.filter
对一个数组实现类型安全的过滤?
const numbers: (string | number)[] = [1, "a", 2, "b"];
const numbersOnly = numbers.filter(
(item): item is number => typeof item === "number"
);
// numbersOnly 类型为 number[]
Q3:类型谓词在运行时如何工作?
- 类型谓词本质是一个返回布尔值的函数,其类型信息仅在编译时存在(会被擦除为普通 JavaScript)。
六、最佳实践
- 在需要区分联合类型或验证复杂数据结构时使用。
- 确保类型谓词的逻辑与断言严格匹配。
特性 | 说明 |
---|---|
语法 | value is Type |
作用 | 运行时检查 + 编译时类型收窄 |
典型场景 | 联合类型区分、复杂对象验证、数组过滤 |
优势 | 比 as 更安全,比普通布尔函数更精准 |
注意事项 | 逻辑需与断言一致,避免滥用 |
更新日志
2025/8/24 08:17
查看所有更新日志
e7112
-1于