详解TypeScript中的类型保护


Posted in Javascript onApril 29, 2021

概述

在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况:

interface Bird {
  	// 独有方法
    fly();
  	// 共有方法
    layEggs();
}

interface Fish {
  	// 独有方法
    swim();
  	// 共有方法
    layEggs();
}

function getSmallPet(): Fish | Bird {
    // ...
}

let pet = getSmallPet();
pet.layEggs(); // 正常
pet.swim();    // ts 报错

如上所示,getSmallPet函数中,既可以返回 Fish 类型的对象,又可以返回 Bird 类型的对象。由于返回的对象类型不确定,所以使用联合类型对象共有的方法时,一切正常,但是使用联合类型对象各自独有的方法时,ts 会报错。

那么如何解决这个问题呢?最粗暴的方法当然是将联合类型转换为 any,不过这种方法不值得提倡,毕竟我们写的是 TypeScript 而不是 AnyScript。

此时,我们使用今天的主角——类型保护,闪亮登场,它可以完美的解决这个问题。

孔乙己说过,茴香豆有四种写法,同理,实现类型保护,也有四种写法。

类型断言

类型断言是最常用的一种类型保护方法,即直接指定类型。由于,TypeScript 中识别的类型大多是靠 TypeScript 的自动类型推算算出来的,所以会出现上面所说的那种问题,即 TypeScript 不知道具体对象类型是什么,所以不确定有没有联合类型各自独有的方法。

当使用类型断言直接指定类型时,相当于你让 TypeScript 开启了上帝模式,可以直接知道具体类型是联合类型中的那个,此时再使用对象的独有方法就符合 TypeScript 的推断了。

interface Bird {
  // 独有方法
  fly();
  // 共有方法
  layEggs();
}

interface Fish {
  // 独有方法
  swim();
  // 共有方法
  layEggs();
}

function getSmallPet(): Fish | Bird {
  // ...
}

let pet = getSmallPet();
pet.layEggs(); // 正常
// 通过鸭子类型来进行判断
if ((pet as Bird).fly) {
  // 类型断言
  (pet as Bird).fly()
} else {
  // 类型断言
  (pet as Fish).swim()
}

如果嫌弃通过 as 来进行类型断言不够上流,还可以使用类泛型的写法,即:

let pet = getSmallPet();
pet.layEggs(); // 正常
// 通过鸭子类型来进行判断
if ((<Bird>pet).fly) {
  (<Bird>pet).fly()
} else {
  (<Fish>pet).swim()
}

tips:友情提示,虽然使用类泛型写法进行类型断言看起来高端一些,但是由于在 tsx 中语法存在歧义,所以为了统一起见,推荐使用 as 的方法进行类型断言。

in语法

在js中,我们经常使用 in 语法来判断指定的属性是否在指定的对象或其原型链中。

同理,在 TypeScript 中,我们可以通过这种方法确认对象类型。

interface Bird {
  // 独有方法
  fly();
  // 共有方法
  layEggs();
}

interface Fish {
  // 独有方法
  swim();
  // 共有方法
  layEggs();
}

function getSmallPet(): Fish | Bird {
  // ...
}

let pet = getSmallPet();
pet.layEggs(); // 正常
// 使用 in 语法进行类型保护
if ('fly' in pet) {
  pet.fly()
} else {
  pet.swim()
}

原理同类型断言一样,都是引导 TypeScript 的类型推断,确定对象类型。

instanceof 语法

当联合类型中使用的是 class 而不是 interface 时,instanceof 语法就派上用场了,通过 instanceof 语法可以区分不同的 class 类型。

class Bird {
  // 独有方法
  fly() {};
  // 共有方法
  layEggs() {};
}

class Fish {
  // 独有方法
  swim() {};
  // 共有方法
  layEggs() {};
}

function getSmallPet(): Fish | Bird {
  // ...
}

let pet = getSmallPet();
pet.layEggs(); // 正常
// 使用 in 语法进行
if (pet instanceof Bird) {
  pet.fly()
} else {
  pet.swim()
}

typeof 语法

typeof 语法不同于 in 语法以及 instanceof 语法,in 语法以及 instanceof 语法都是用来引导类型推断进行不同对象类型推断,而 typeof 语法常用于基本类型的推断(或者是联合使用基本类型和对象类型)。

简而言之,当使用 typeof 能够区分联合类型中的不同类型时,即可使用它。

function getSmallPet(): number | string {
  // ...
}

let pet = getSmallPet();
if (typeof pet === 'number') {
  pet++
} else {
  pet = Number(pet) + 1
}

总结

就如茴香豆的四种写法的本质依然是茴香豆一样,类型保护的四种写法的本质也是一样的,即,引导 TypeScript 中的类型推断将类型推断的多选题变为单选题,这就是类型保护的本质。

以上就是详解TypeScript中的类型保护的详细内容,更多关于TypeScript类型保护的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JQuery.get提交页面不跳转的解决方法
Jan 13 Javascript
jQuery原生的动画效果
Jul 10 Javascript
Javascript实现图片轮播效果(一)让图片跳动起来
Feb 17 Javascript
js模式化窗口问题![window.dialogArguments]
Oct 30 Javascript
Bootstrap php制作动态分页标签
Dec 23 Javascript
详解AngularJS验证、过滤器、指令
Jan 04 Javascript
JS实现最简单的冒泡排序算法
Feb 15 Javascript
JS表单提交验证、input(type=number) 去三角 刷新验证码
Jun 21 Javascript
vue router自动判断左右翻页转场动画效果
Oct 10 Javascript
Bootstrap3.3.7导航栏下拉菜单鼠标滑过展开效果
Oct 31 Javascript
JS定义函数的几种常用方法小结
May 23 Javascript
Layui弹框中数据表格中可双击选择一条数据的实现
May 06 Javascript
7个你应该知道的JS原生错误类型
Apr 29 #Javascript
使用vue-element-admin框架从后端动态获取菜单功能的实现
如何使用JavaScript策略模式校验表单
Apr 29 #Javascript
react中props 的使用及进行限制的方法
Apr 28 #Javascript
React Hook用法示例详解(6个常见hook)
vue使用v-model进行跨组件绑定的基本实现方法
为什么node.js不适合大型项目
You might like
php创建sprite
2014/02/11 PHP
php生成年月日下载列表的方法
2015/04/24 PHP
PHPStorm+XDebug进行调试图文教程
2016/06/13 PHP
微信支付开发交易通知实例
2016/07/12 PHP
PHP入门教程之PHP操作MySQL的方法分析
2016/09/11 PHP
php+redis在实际项目中HTTP 500: Internal Server Error故障排除
2017/02/05 PHP
php模仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(中)
2017/06/11 PHP
jQuery中get和post方法传值测试及注意事项
2014/08/08 Javascript
基于nodejs+express(4.x+)实现文件上传功能
2015/11/23 NodeJs
js动态生成form 并用ajax方式提交的实现方法
2016/09/09 Javascript
vuejs动态组件给子组件传递数据的方法详解
2016/09/09 Javascript
jQuery tagsinput在h5邮件客户端中应用详解
2016/09/26 Javascript
BootStrap实现带关闭按钮功能
2017/02/15 Javascript
vue.js利用defineProperty实现数据的双向绑定
2017/04/28 Javascript
JavaScript简单拖拽效果(1)
2017/05/17 Javascript
浅析vue中常见循环遍历指令的使用 v-for
2018/04/18 Javascript
利用js将ajax获取到的后台数据动态加载至网页中的方法
2018/08/08 Javascript
layer弹出的iframe层在执行完毕后关闭当前弹出层的方法
2018/08/17 Javascript
[01:00:10]完美世界DOTA2联赛PWL S2 FTD vs Inki 第二场 11.21
2020/11/24 DOTA
Python编写Windows Service服务程序
2018/01/04 Python
Python实现的求解最大公约数算法示例
2018/05/03 Python
Python多进程与服务器并发原理及用法实例分析
2018/08/21 Python
opencv之为图像添加边界的方法示例
2019/12/26 Python
jupyter 导入csv文件方式
2020/04/21 Python
打印机墨盒:123Inkjets
2017/02/16 全球购物
瑞典度假品牌:OAS
2019/05/28 全球购物
雅虎笔试题(字符串操作)
2015/03/24 面试题
生产主管岗位职责
2013/11/10 职场文书
实习鉴定范文
2013/12/19 职场文书
教师个人自我鉴定
2014/02/08 职场文书
《一个小村庄的故事》教学反思
2014/04/13 职场文书
宿舍标语大全
2014/06/19 职场文书
公司行政主管岗位职责
2015/04/09 职场文书
Pygame Time时间控制的具体使用详解
2021/11/17 Python
电脑无法安装Windows 11怎么办?无法安装Win11的解决方法
2021/11/21 数码科技
Nginx使用ngx_http_upstream_module实现负载均衡功能示例
2022/08/05 Servers