详解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 相关文章推荐
用js 让图片在 div或dl里 居中,底部对齐
Jan 21 Javascript
动态表格Table类的实现
Aug 26 Javascript
js去字符串前后空格5种实现方法及比较
Apr 03 Javascript
JSON 数字排序多字段排序介绍
Sep 18 Javascript
Jquery AJAX POST与GET之间的区别
Nov 14 Javascript
jquery的clone方法应用于textarea和select的bug修复
Jun 26 Javascript
jquery实现用户打分评分特效
May 28 Javascript
vue中v-cloak解决刷新或者加载出现闪烁问题(显示变量)
Apr 20 Javascript
Vue 父子组件数据传递的四种方式( inheritAttrs + $attrs + $listeners)
May 04 Javascript
jQuery内容过滤选择器与子元素过滤选择器用法实例分析
Feb 20 jQuery
基于PHP pthreads实现多线程代码实例
Jun 24 Javascript
JavaScript语句错误throw、try及catch实例解析
Aug 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
轻松修复Discuz!数据库
2008/05/03 PHP
php自动跳转中英文页面
2008/07/29 PHP
PHP入门教程之正则表达式基本用法实例详解(正则匹配,搜索,分割等)
2016/09/11 PHP
Javascript 获取滚动条位置等信息的函数
2009/09/08 Javascript
firefox下jquery ajax返回object XMLDocument处理方法
2014/01/26 Javascript
JS完整获取IE浏览器信息包括类型、版本、语言等等
2014/05/22 Javascript
jQuery跨域问题解决方案
2015/08/03 Javascript
基于jQuery 实现bootstrapValidator下的全局验证
2015/12/07 Javascript
基于JavaScript实现文字超出部分隐藏
2016/02/29 Javascript
bootstrap laydate日期组件使用详解
2017/01/04 Javascript
angularjs实现多张图片上传并预览功能
2017/02/24 Javascript
vue cli升级webapck4总结
2018/04/04 Javascript
Angular 利用路由跳转到指定页面的指定位置方法
2018/08/31 Javascript
Node.js API详解之 tty功能与用法实例分析
2020/04/27 Javascript
基于vue中的scoped坑点解说
2020/09/04 Javascript
浅析VUE防抖与节流
2020/11/24 Vue.js
[52:09]2014 DOTA2华西杯精英邀请赛 5 25 NewBee VS DK第二场
2014/05/26 DOTA
基于python的Tkinter实现一个简易计算器
2015/12/31 Python
利用Python中unittest实现简单的单元测试实例详解
2017/01/09 Python
python实现报表自动化详解
2017/11/16 Python
详解TensorFlow查看ckpt中变量的几种方法
2018/06/19 Python
python list格式数据excel导出方法
2018/10/31 Python
TensorFlow打印输出tensor的值
2020/04/19 Python
Python txt文件常用读写操作代码实例
2020/08/03 Python
css3中background新增的4个新的相关属性用法介绍
2013/09/26 HTML / CSS
美国知名日用品连锁超市:Dollar General(多来店)
2017/01/14 全球购物
植物选择:Botanic Choice
2017/02/15 全球购物
美国流行背包品牌:JanSport(杰斯伯)
2018/03/02 全球购物
Marlies Dekkers内衣法国官方网上商店:国际知名的荷兰内衣品牌
2019/03/18 全球购物
美国在线购物频道:Shop LC
2019/04/21 全球购物
大学生志愿者感言
2014/01/15 职场文书
班主任2015新年寄语
2014/12/08 职场文书
2014年校长工作总结
2014/12/11 职场文书
社会实践心得体会范文
2016/01/14 职场文书
python获取字符串中的email
2022/03/31 Python
MYSQL常用函数介绍
2022/05/05 MySQL