将类型提炼为比定义时更具体类型的过程称为类型收窄。下面会详细分析不同的类型收窄方式。
typeof
typeof 是 javascript 的一个运算符,它可以在运行时提供当前值的类型信息,因此可以借助 typeof 实现类型收窄。它可以判断的类型有 string,number,boolean,undefined,symbol,bigint,object,function,看起来能够判断很多类型,可是它却有一个缺陷,就是会把 null 类型判断为 object。
当 value 的类型是 object 的时候,也就是将传入的值限定为数组,可以使用 for...of 进行遍历。但是这里面忽视了 value 为 null 的情况,因此会出现类型错误。解决方式限定 value 为 object 的同时还要加上非 null 的判断,也就是 typeof value === 'object' && value !== null
真值收窄
可以在条件判断的时候强制转成布尔值,这样就可以限制值的类型。转化成 false 的情况比较少,包括0,null,undefined,0n,NaN,'',其他情况都可以转化成 true。上面的非 null 限定可以修改为 typeof value === 'object' && value,这样也排除了 value 为 null 的情况。
相等收窄
typescript 可以使用 ===,!==,==,!= 和 switch 语句等方式进行类型缩小,其实 typeof value === 'object' && value !== null 就是使用相等收窄。
in
javascript 中使用 in 来判断对象是否有某个属性,而 typescript 则是用来缩小可能的类型。
type Fish = { swim: () => void }
type Bird = { fly: () => void }
type Human = { swim: () => void, fly?: () => void }
function move(type: Fish | Bird | Human) {
if ('fly' in type) {
// (parameter) type: Bird | Human
} else {
// (parameter) type: Fish | Human
}
}
可选属性 fly 遇到 in 的时候,它会包含两种情况,也就是说 Human 类型有可能包含 fly 属性,也有可能不包含。
instanceof
javascript 使用 instanceof 来判断一个值是否在另一个值的原型链上,typescript 中 instanceof 也是类型保护的一种,常用在使用 class 或者 new 的场景中。
function test(value: Date | string) {
if (value instanceof Date) {
// (parameter) value: Date
} else {
// (parameter) value: string
}
}
这里的 value 如果是 Date 的实例就放行,否则就判断为 string 类型。
小结
类型收窄有很多种方式,包括 typeof,in,instanceof,真值,相等等。本质上就是通过判断限制传参的类型从而达到类型收窄。