详解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 相关文章推荐
Javascript中找到子元素在父元素内相对位置的代码
Jul 21 Javascript
JS操作数据库的实例代码
Oct 17 Javascript
javascript获取浏览器类型和版本的方法(js获取浏览器版本)
Mar 13 Javascript
Jquery实现兼容各大浏览器的Enter回车切换输入焦点的方法
Sep 01 Javascript
JavaScript实现同步于本地时间的动态时间显示方法
Feb 02 Javascript
基于Bootstrap使用jQuery实现简单可编辑表格
May 04 Javascript
详细探究ES6之Proxy代理
Jul 22 Javascript
vue的toast弹窗组件实例详解
May 14 Javascript
vue权限路由实现的方法示例总结
Jul 29 Javascript
vue element动态渲染、移除表单并添加验证的实现
Jan 16 Javascript
JS+CSS+HTML实现“代码雨”类似黑客帝国文字下落效果
Mar 17 Javascript
如何用JS模拟实现数组的map方法
Jul 30 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
关于Appserv无法打开localhost问题的解决方法
2009/10/16 PHP
php单例模式实现(对象只被创建一次)
2012/12/05 PHP
PHP操作MongoDB GridFS 存储文件的详解
2013/06/20 PHP
Linux基于php-fpm模式的lamp搭建phpmyadmin的方法
2018/10/25 PHP
解放web程序员的输入验证
2006/10/06 Javascript
极酷的javascirpt,让你随意编辑任何网页
2007/02/25 Javascript
捕获和分析JavaScript Error的方法
2014/03/25 Javascript
简介JavaScript中toTimeString()方法的使用
2015/06/12 Javascript
js代码实现无缝滚动(文字和图片)
2015/08/20 Javascript
基于JS代码实现当鼠标悬停表格上显示这一格的全部内容
2016/06/12 Javascript
KnockoutJS 3.X API 第四章之表单value绑定
2016/10/10 Javascript
JS实现移动端实时监听输入框变化的实例代码
2017/04/12 Javascript
Angular 5.0 来了! 有这些大变化
2017/11/15 Javascript
详解关于element级联选择器数据回显问题
2019/02/20 Javascript
javascript操作元素的常见方法小结
2019/11/13 Javascript
Python 初始化多维数组代码
2008/09/06 Python
Python2.x中文乱码问题解决方法
2015/06/02 Python
利用python实现数据分析
2017/01/11 Python
Python操作mysql数据库实现增删查改功能的方法
2018/01/15 Python
python使用tkinter实现简单计算器
2018/01/30 Python
Django进阶之CSRF的解决
2018/08/01 Python
对Pytorch中nn.ModuleList 和 nn.Sequential详解
2019/08/18 Python
Python模块汇总(常用第三方库)
2019/10/07 Python
利用 PyCharm 实现本地代码和远端的实时同步功能
2020/03/23 Python
Selenium python时间控件输入问题解决方案
2020/07/22 Python
python 获取字典特定值对应的键的实现
2020/09/29 Python
thinkphp5 路由分发原理
2021/03/18 PHP
canvas实现圆绘制的示例代码
2019/09/11 HTML / CSS
详解Html5中video标签那些属性和方法
2019/07/01 HTML / CSS
DJI大疆无人机官方商城:全球领先的无人飞行器研发和生产商
2016/12/21 全球购物
造型师求职自荐信
2013/09/27 职场文书
国际贸易个人求职信范文
2014/01/04 职场文书
园艺师求职信
2014/04/27 职场文书
社区精神文明建设汇报材料
2014/08/17 职场文书
节约用电倡议书
2015/04/28 职场文书
“鬼灭之刃”热度不减,其成功背后的原因是什么?
2022/03/22 日漫