0%

typescript-type-predicate

介绍

各位老铁上午好,昨天我们学习了TypeScript中的类型断言(as操作符),今天我们来学习TypeScript中的类型谓词(Type Predicate)(is操作符)。

为什么需要类型谓词呢?我们先看一个例子,假设我们要写一个函数,判断一个变量是否为字符串类型。

1
2
3
function isString(value: unknown): boolean {
return typeof value === 'string';
}

调用这个函数

1
2
3
4
5
6
7
8
function example(foo: any) {
if (isString(foo)) {
console.log(foo.toUpperCase()); // 这里会报错,因为foo的类型仍然是any
}
}

example("hello"); // 输出 "HELLO"
example(123); // 不会输出任何内容

看起来一切正常,但是假如我们疏忽了,不小心在example中调用了一个不属于字符串的方法,比如toFixed,TypeScript会报错,因为字符串上没有toFixed方法。

1
2
3
4
5
6
7
function example(foo: any) {
if (isString(foo)) { // foo的类型是any,通过检查
console.log(foo.toFixed(2)); // 编译时没有问题
}
}

example("hello"); // 运行时报错,因为字符串上没有toFixed方法

在上面的代码中,虽然满足了isString()的判断,但是在编译期间,foo还是它本来的类型,typescript无法在编译期检查到错误。

但是,如果我们加上类型谓词,IDE就会提示字符串上没有toFixed方法。也就是说,类型谓词可以在编译时就杜绝类型错误,这就是它核心的功能。

1
2
3
function isString(value: unknown): value is string {
return typeof value === 'string';
}

上面的代码中,typescript在编译期就会将value的类型窄化为string,如果调用的方法不属于string类型,IDE会提示错误。

1
2
3
4
5
6
function example(foo: any) {
if (isString(foo)) {
// TS2551: Property 'toFixed' does not exist on type 'string'.
console.log(foo.toFixed(2)); // 编译期报错
}
}

类型谓词的语法规则

类型谓词要写在函数的返回值上,形式为:value is Type,其中value是函数的参数,Type是要判断的类型,比如一个判断number类型的函数可以这样写:

1
2
3
function isNumber(value: unknown): value is number {
return typeof value === 'number';
}

类型谓词的作用范围

需要注意的是,类型谓词只在isString函数的作用域内有效。也就是说,只有在isString函数返回true的情况下,TypeScript才会将传入的参数类型窄化为string

1
2
3
4
5
6
7
8
9
function example(foo: any) {
if (isString(foo)) {
console.log(foo.toFixed()); // 编译期报错,因为foo的类型被窄化为string
}

console.log(foo.toFixed()); // 运行时报错,因为foo的类型仍然是any
}

example("hello");

好了,今天就到这里了,我们明天见。

今天又买了一把新弹弓:锁凤十代,握感舒适,重量适中。理查德说这个弓可以留着,我再试两天再说。