跳到主要内容

TypeScript 类型保护

本节介绍的类型保护 TypeScript 类型检查机制的第二个部分,我们可以通过 typeofinstanceofin字面量类型 将代码分割成范围更小的代码块,在这一小块中,变量的类型是确定的。

1. 慕课解释

类型保护是指缩小类型的范围,在一定的块级作用域内由编译器推导其类型,提示并规避不合法的操作。

2. typeof

通过 typeof 运算符判断变量类型,下面看一个之前介绍函数重载时的例子:

function reverse(target: string | number) {
if (typeof target === 'string') {
target.toFixed(2) // Error,在这个代码块中,target 是 string 类型,没有 toFixed 方法
return target.split('').reverse().join('')
}
if (typeof target === 'number') {
target.toFixed(2) // OK
return +[...target.toString()].reverse().join('')
}

target.forEach(element => {}) // Error,在这个代码块中,target 是 string 或 number 类型,没有 forEach 方法
}

代码解释:

第 2 行,通过 typeof 关键字,将这个代码块中变量 target 的类型限定为 string 类型。

第 6 行,通过 typeof 关键字,将这个代码块中变量 target 的类型限定为 number 类型。

第 11 行,因没有限定,在这个代码块中,变量 target 是 string 或 number 类型,没有 forEach 方法,所以报错。

3. instanceof

instanceof 与 typeof 类似,区别在于 typeof 判断基础类型,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
}
}

代码解释:

第 12 行,通过 instanceof 关键字,将这个代码块中变量 arg 的类型限定为 User 类型。

第 16 行,通过 instanceof 关键字,将这个代码块中变量 arg 的类型限定为 Log 类型。

4. in

in 操作符用于确定属性是否存在于某个对象上,这也是一种缩小范围的类型保护。

class User {
public nickname: string | undefined
public groups!: number[]
}

class Log {
public count: number = 10
public keyword: string | undefined
}

function typeGuard(arg: User | Log) {
if ('nickname' in arg) {
// (parameter) arg: User,编辑器将推断在当前块作用域 arg 为 User 类型
arg.nickname = 'imooc'
}

if ('count' in arg) {
// (parameter) arg: Log,编辑器将推断在当前块作用域 arg 为 Log 类型
arg.count = 15
}
}

代码解释:

第 12 行,通过 in 关键字,将这个代码块中变量 arg 的类型限定为 User 类型。

第 17 行,通过 in 关键字,将这个代码块中变量 arg 的类型限定为 Log 类型。

5. 字面量类型保护

用字面量类型那一节的例子改造一下来介绍字面量类型保护:

type Success = {
success: true,
code: number,
object: object
}

type Fail = {
success: false,
code: number,
errMsg: string,
request: string
}

function test(arg: Success | Fail) {
if (arg.success === true) {
console.log(arg.object) // OK
console.log(arg.errMsg) // Error, Property 'errMsg' does not exist on type 'Success'
} else {
console.log(arg.errMsg) // OK
console.log(arg.object) // Error, Property 'object' does not exist on type 'Fail'
}
}

代码解释:

第 15 行,通过布尔字面量,将这个代码块中变量 arg 的类型限定为 Success 类型。

第 18 行,通过布尔字面量,将这个代码块中变量 arg 的类型限定为 Fail 类型。

6. 小结

类型保护就是让编译器帮助我们缩小类型范围,在编译阶段规避掉一些不必要的错误,提高代码质量。