详解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 相关文章推荐
Firefox outerHTML实现代码
Jun 04 Javascript
editable.js 基于jquery的表格的编辑插件
Oct 24 Javascript
浅析jquery的作用与优势
Dec 02 Javascript
JavaScript 表单处理实现代码
Apr 13 Javascript
javascript实现秒表计时器的制作方法
Feb 16 Javascript
JS实现身份证输入框的输入效果
Aug 21 Javascript
Angular移动端页面input无法输入的解决方法
Nov 14 Javascript
vue-cli启动本地服务局域网不能访问的原因分析
Jan 22 Javascript
动态内存分配导致影响Javascript性能的问题
Dec 18 Javascript
详解微信小程序实现仿微信聊天界面(各种细节处理)
Feb 17 Javascript
微信小程序停止其他视频播放当前视频的实例代码
Dec 25 Javascript
微信小程序实现多张图片上传功能
Nov 18 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
模拟OICQ的实现思路和核心程序(三)
2006/10/09 PHP
php下载远程文件类(支持断点续传)
2008/11/14 PHP
php删除文件夹及其文件夹下所有文件的函数代码
2013/01/23 PHP
解析Extjs与php数据交互(增删查改)
2013/06/25 PHP
10个超级有用的PHP代码片段果断收藏
2015/09/23 PHP
PHP函数import_request_variables()用法分析
2016/04/02 PHP
Laravel 5.4.36中session没有保存成功问题的解决
2018/02/19 PHP
实例讲解PHP中使用命名空间
2019/01/27 PHP
javascript从右边截取指定字符串的三种实现方法
2013/11/29 Javascript
从js向Action传中文参数出现乱码问题的解决方法
2013/12/29 Javascript
javascript中兼容主流浏览器的动态生成iframe方法
2014/05/05 Javascript
JQuery实现防止退格键返回的方法
2015/02/12 Javascript
如何用js实现鼠标向上滚动时浮动导航
2016/07/18 Javascript
nodejs+websocket实时聊天系统改进版
2017/05/18 NodeJs
详解ES6中的三种异步解决方案
2018/06/28 Javascript
解决Vue的文本编辑器 vue-quill-editor 小图标样式排布错乱问题
2020/08/03 Javascript
ES11屡试不爽的新特性,你用上了几个
2020/10/21 Javascript
node中短信api实现验证码登录的示例代码
2021/01/20 Javascript
利用 Chrome Dev Tools 进行页面性能分析的步骤说明(前端性能优化)
2021/02/24 Javascript
[02:43]2014DOTA2国际邀请赛 官方Alliance战队纪录片
2014/07/14 DOTA
零基础写python爬虫之打包生成exe文件
2014/11/06 Python
python中while循环语句用法简单实例
2015/05/07 Python
详解Python的Django框架中的模版继承
2015/07/16 Python
详解用python实现简单的遗传算法
2018/01/02 Python
Python 查找list中的某个元素的所有的下标方法
2018/06/27 Python
pyqt5实现登录界面的模板
2020/05/30 Python
python列表推导式操作解析
2019/11/26 Python
Python彻底删除文件夹及其子文件方式
2019/12/23 Python
Python基于Serializer实现字段验证及序列化
2020/11/04 Python
HTML5中的强制下载属性download使用实例解析
2016/05/12 HTML / CSS
ASOS比利时:英国线上零售商及自有品牌
2018/07/29 全球购物
英文版餐饮运营管理求职信
2013/11/06 职场文书
创建省级文明单位实施方案
2014/02/27 职场文书
教师党员自我剖析材料
2014/09/29 职场文书
联谊会开场白
2015/06/01 职场文书
使用 MybatisPlus 连接 SqlServer 数据库解决 OFFSET 分页问题
2022/04/22 SQL Server