详解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 相关文章推荐
Display SQL Server Login Mode
Jun 21 Javascript
批量实现面向对象的实例代码
Jul 01 Javascript
jquery实现勾选复选框触发事件给input赋值
Feb 01 Javascript
readonly和disabled属性的区别
Jul 26 Javascript
socket.io与pm2(cluster)集群搭配的解决方案
Jun 02 Javascript
详解React Native 屏幕适配(炒鸡简单的方法)
Jun 11 Javascript
浅谈vue.use()方法从源码到使用
May 12 Javascript
微信小程序中如何计算距离某个节日还有多少天
Jul 15 Javascript
vue keep-alive 动态删除组件缓存的例子
Nov 04 Javascript
JS Ajax请求会话过期处理问题解决方法分析
Nov 16 Javascript
three.js着色器材质的内置变量示例详解
Aug 16 Javascript
Selenium执行JavaScript脚本的方法示例
Dec 31 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通过记录IP来防止表单重复提交方法分析
2014/12/16 PHP
Zend Framework动作助手Redirector用法实例详解
2016/03/05 PHP
PHP Static延迟静态绑定用法分析
2016/03/16 PHP
解决火狐浏览器下JS setTimeout函数不兼容失效不执行的方法
2012/11/14 Javascript
jQuery 遍历-nextUntil()方法以及prevUntil()方法的使用介绍
2013/04/26 Javascript
js实现右下角提示框的方法
2015/02/03 Javascript
深入分析Javascript跨域问题
2015/04/17 Javascript
教你用javascript实现随机标签云效果_附代码
2016/03/16 Javascript
jQuery针对input的class属性写了多个值情况下的选择方法
2016/06/03 Javascript
返回函数的JavaScript函数
2016/06/14 Javascript
jQuery中 $ 符号的冲突问题及解决方案
2016/11/04 Javascript
详解jQuery停止动画——stop()方法的使用
2016/12/14 Javascript
AngularJS开发教程之控制器之间的通信方法分析
2016/12/25 Javascript
JavaScript循环_动力节点Java学院整理
2017/06/28 Javascript
利用百度地图API获取当前位置信息的实例
2017/11/06 Javascript
微信小程序实现选项卡功能
2020/06/19 Javascript
VUE2.0+ElementUI2.0表格el-table循环动态列渲染的写法详解
2018/11/30 Javascript
解决layer弹出层自适应页面大小的问题
2019/09/16 Javascript
解决layui追加或者动态修改的表单元素“没效果”的问题
2019/09/18 Javascript
使用Webpack 搭建 Vue3 开发环境过程详解
2020/07/28 Javascript
[01:08]2014DOTA2展望TI 剑指西雅图LGD战队专访
2014/06/30 DOTA
python写的ARP攻击代码实例
2014/06/04 Python
Python网络编程之TCP与UDP协议套接字用法示例
2018/02/02 Python
python或C++读取指定文件夹下的所有图片
2019/08/31 Python
Python分割训练集和测试集的方法示例
2019/09/19 Python
python pycharm最新版本激活码(永久有效)附python安装教程
2020/09/18 Python
Canvas多边形绘制的实现方法
2019/08/05 HTML / CSS
建筑工程管理专业自荐信范文
2013/12/28 职场文书
事业单位接收函
2014/01/10 职场文书
人力资源部经理岗位职责规定
2014/02/23 职场文书
《恐龙》教学反思
2014/04/27 职场文书
应届生找工作求职信
2014/06/24 职场文书
律政俏佳人观后感
2015/06/09 职场文书
劳动合同变更协议书范本
2019/04/18 职场文书
超级实用!五步法则,教你写好年终工作总结
2019/12/05 职场文书
Oracle数据库中通用的函数实例详解
2022/03/25 Oracle