文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
十四、类型检查机制
14.1 类型检查机制
编译器在做类型检查时,秉承的一些原则,表现出的一些行为
作用:辅助开发,提高开发效率
- 类型推断
- 类型兼容性
- 类型保护
所谓类型推断:不需要指定变量的类型(函数的返回值类型),TS 可以根据某些规则自动的为其推断出一个类型
- 基础类型推断
- 最佳通用类型推断
- 上下文类型推断
基础类型推断,从右向左。但是有些是从左向右推断
如事件
// ts 根据 onkeydown 推断出类型 window.onkeydown = event=>{ console.log(event) }
通过类型断言阻断 TS 的类型推断
interface Foo { bar: number } //let foo = {} as Foo //foo.bar = 1 let foo: Foo = { bar: 1 }
14.2 类型保护机制
联合类型适合于那些值可以为不同类型的情况。 但当我们想确切地了解是否为 Fish 或者是 Bird 时怎么办? JavaScript 里常用来区分这 2 个可能值的方法是检查成员是否存在。如之前提及的,我们只能访问联合类型中共同拥有的成员
不同的判断方法有不同的使用场景:
typeof
:判断一个变量的类型instanceof
:判断一个实例是否属于某个类in
:判断一个属性是否属于某个对象- 类型保护函数:某些判断可能不是一条语句能够搞定的,需要更多复杂的逻辑,适合封装到一个函数内
function getLanguage(type: Type) { let lang = type === type.Strong ? new Java(): new Javascript() // 类型保护 instanceof if(lang instanceof Java){ lang.hellJava() }else { lang.hellJavaScript() } // in if('java' in lang) { lang.hellJava() }else { lang.hellJavaScript() } // 类型保护函数方式 if(isJava(lang)) { lang.hellJava() }else { lang.hellJavaScript() } } // 创建一种类型保护函数 function isJava(lang: Java | Javascript): lang is Java { // 类型断言 return (lang as Java).lang.helloJava !== undefined }
let pet = getSmallPet() // 每一个成员访问都会报错 if (pet.swim) { pet.swim() } else if (pet.fly) { pet.fly() }
为了让这段代码工作,我们要使用类型断言
let pet = getSmallPet() if ((pet as Fish).swim) { (pet as Fish).swim() } else { (pet as Bird).fly() }
14.2.1 用户自定义的类型保护
- 这里可以注意到我们不得不多次使用类型断言。如果我们一旦检查过类型,就能在之后的每个分支里清楚地知道
pet
的类型的话就好了。 TypeScript
里的类型保护机制让它成为了现实。 类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型。定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个类型谓词
function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined }
- 在这个例子里,
pet is Fish
就是类型谓词。谓词为parameterName is Type
这种形式,parameterName
必须是来自于当前函数签名里的一个参数名。 - 每当使用一些变量调用
isFish
时,TypeScript 会将变量缩减为那个具体的类型
if (isFish(pet)) { pet.swim() } else { pet.fly() }
注意 TypeScript 不仅知道在 if
分支里 pet
是 Fish
类型;它还清楚在 else
分支里,一定不是 Fish
类型而是 Bird
类型
14.2.2 typeof 类型保护
我们可以像下面这样利用类型断言来写
function isNumber (x: any):x is string { return typeof x === 'number' } function isString (x: any): x is string { return typeof x === 'string' } function padLeft (value: string, padding: string | number) { if (isNumber(padding)) { return Array(padding + 1).join(' ') + value } if (isString(padding)) { return padding + value } throw new Error(`Expected string or number, got '${padding}'.`) }
然而,你必须要定义一个函数来判断类型是否是原始类型,但这并不必要。其实我们不必将 typeof x === 'number'
抽象成一个函数,因为 TypeScript 可以将它识别为一个类型保护。 也就是说我们可以直接在代码里检查类型了
function padLeft (value: string, padding: string | number) { if (typeof padding === 'number') { return Array(padding + 1).join(' ') + value } if (typeof padding === 'string') { return padding + value } throw new Error(`Expected string or number, got '${padding}'.`) }
这些 typeof
类型保护只有两种形式能被识别: typeof v === "typename"
和 typeof v !== "typename"
, "typename"
必须是 "number"
, "string"
, "boolean"
或 "symbol"
。 但是 TypeScript 并不会阻止你与其它字符串比较,只是 TypeScript 不会把那些表达式识别为类型保护。
14.2.3 instanceof 类型保护
- 如果你已经阅读了
typeof
类型保护并且对 JavaScript 里的instanceof
操作符熟悉的话,你可能已经猜到了这节要讲的内容。 instanceof
类型保护是通过构造函数来细化类型的一种方式。我们把之前的例子做一个小小的改造:
class Bird { fly () { console.log('bird fly') } layEggs () { console.log('bird lay eggs') } } class Fish { swim () { console.log('fish swim') } layEggs () { console.log('fish lay eggs') } } function getRandomPet () { return Math.random() > 0.5 ? new Bird() : new Fish() } let pet = getRandomPet() if (pet instanceof Bird) { pet.fly() } if (pet instanceof Fish) { pet.swim() }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论