概念
在语句的块级作用域【if语句内或条目运算符表达式内】缩小变量类型的一种类型推断的行为。
类型守卫可以帮助我们在块级作用域中获得更为需要的精确变量类型,从而减少不必要的类型断言。
- 类型判断:
typeof
- 实例判断:
instanceof
- 字面量相等判断:
==
,===
,!=
,!==
类型判断(typeof)
function test(own: string | boolean | number) {
if (typeof own === "string") {
// 这里own的类型限制为string
} else if (typeof own === "number") {
// 这里 own 的类型限制为 number
} else {
// 这里的类型限制为 boolean
}
}
很好理解吧,就像JS的typeof一样。但是两者还是有区别的。
typeof
类型保护只支持两种形式:
typeof value === [typename]
typeof value !== [typename]
这里"typename"
必须是"number"
,"string"
,"boolean"
或"symbol"
。但是 TypeScript 并不会阻止你与其它字符串比较,只是语言不会把那些表达式识别为类型保护。
转成JS几乎无区别。
虽然在类型判断里ts的typeof和js的typeof看起来没有区别。但是。ts的typeof用法与js的typeof用法存在蛮大的差异。具体可以看这篇推文。
实例判断instanceof (对typeof的补充)
js里也有instanceof。instance就是实例的意思,建议先看看JS里instanceof和typeof的区别。
在 TypeScript 中,使用 instanceof 操作符可以检查一个对象是否是某个类的实例。当我们在使用类时,可以通过 instanceof 检查来确认一个实例是否符合该类的定义
class User {
public nickname: string | undefined
public group: number | undefined
}
class Log {
public count: number = 10
public keyword: string | undefined
}
function typeGuard(arg: User | Log) {
if (arg instanceof User) {
arg.count = 15 // Error, User 类型无此属性
}
if (arg instanceof Log) {
arg.count = 15 // OK
}
}
为什么用instanceof呢?因为typeof有局限性,引用类型比如数组,正则等无法精确识别是哪一个种型,instanceof能够识别变量(比如实例对象)是否属于这个类。
但是注意,interface接口是不能用instanceof去检查。 接口的 instanceof 检查需要类型谓词。
interface Foo {...}
interface Bar {...}
function test(input: Foo | Bar) {
if (input instanceof Foo) {
// 这里 input 的类型「收紧」为 Foo
} else {
// 这里 input 的类型「收紧」为 Bar
}
}
上面是错误的写法,正确的方法可以看这篇推文
in关键字
interface one {
name: string;
speak: string;
}
interface two {
age: number;
see: string;
}
先写两个接口one、two(不懂接口的可以看我这篇文章),然后将这两个接口进行联合声明一种混合类型。
type customType = one | two;
使用in
来判断属性是否在传递的参数中,然后分别作输出。类似于在JS中我们根据特定的属性判断这个对象是我们要找的哪个对象。
function test(value: one | two) {
// function test(value: type) {
if("name" in value) {
// 因为有name 这里收紧为value 对象为 one
console.log(value.speak);
}
if("see" in value) {
// 因为有see 这里收紧为value 对象为 two
console.log(value.see);
}
}
缺点:用 in 关键字缩小数据类型至少有一个独特的属性作为判别标准,否则不能用 in 关键字