TypeScript 联合类型(union type)

TS是JS的超集,在JS的基础上添加了一套类型系统,这样的TS可以被静态分析带来的好处显而易见。

let val: string = 'val';

声明一个string类型的变量val

let val: string = 'val';
val = 1; // Type 'number' is not assignable to type 'string'.

因为number类型和string类型并不兼容,在string类型值出现的地方并不能使用number类型指完成替换,所以在TS世界中给string类型的val变量赋值number类型的值会报错。

但是在JS中并没有赋值的限制:

// javascript
var val = 'val';
val = 1; // 这里不会报错

在JS中变量val首先被赋值了字符串,然后被赋值了数字,这两个数据类型并不一致,但是因为JS没有静态类型检查,所以这并不会报错。

TS的联合类型可以适应这种情况,表示这个变量可能是类型a也可能是类型b也可能是类型c等类型。

let val: string | number = 'val'
val = 1 // 这里并不会报错

在TS中,这里声明的变量val则表示可能是类型string也可能是类型number,所以对变量赋值string类型值和number类型值,并不会报错。

但问题也随之而来。

function test(val: string | number) {val.toLowerCase() // Property 'toLowerCase' does not exist on type 'string | number'.
}

TS会提示类型 string | number 上没有属性toLowserCase。

这个报错也很容易理解,因为类型string的数据上可以调用方法toLowerCase,但是number不可以。因为变量val的类型,string和number都有可能,TS并不能确定val在运行时是string类型,所以会出现这个错误。

我们需要一个方法来告诉TS这个变量现在是string类型。

使用typeof缩小类型范围

对于上面例子中的变量val.toLowerCase的报错来说是因为val的类型范围有点大(string | number),如果我们通过某种方式缩小该范围为string,那么在val上访问属性toLowserCase应当没有问题。

function test(val: string | number) {if (typeof val === 'string') {val.toLowerCase() // 这里并不会报错console.log('val是字符串')} else {console.log('val是数字')}
}

在TS中,if中的typeof val === 'string'这种形式的代码会被识别为类型保护(type guard)。TS会分析代码的执行流程,缩小变量可能的类型。在分支if (typeof val === ‘string’) 中变量val的类型被TS识别为’string’,所以在这个分支下val调用string类型数据的方法并不会报错。

因为val是string和number这两个类型的联合,TS不仅知道if子句中的val是string类型,还知道else中的val是number类型。

可以被typeof进行类型保护的类型有:

  • “string”
  • “number”
  • “bigint”
  • “boolean”
  • “symbol”
  • “undefined”
  • “object”
  • “function”

使用in缩小类型范围

上面介绍了对于基础类型的识别,在TS中使用频率更多的还有对象,使用typeof来区别不同对象显然是有问题的,因为typeof出来的结果都是’object’无法分辨两个不同的对象。

type A = {a: string}
type B = {b: string}function test(val: A | B) {val.a // Property 'a' does not exist on type 'A | B'
}

在test函数中无论是访问val.a还是val.b都会报错,而原因已经明白,TS无法确定变量val的具体类型,TS并不知道当前是类型A还是类型B,所以我们需要帮他一把。

type A = {a: string}
type B = {b: string}function test(val: A | B) {if ('a' in val) {console.log(val.a)return}console.log(val.b)
}

其中的in操作同样会被TS识别为类型保护,如果属性a存在于变量val中那么就能识别出val变量是类型A,则可以正常访问类型A中存在的属性a。

使用instanceof缩小类型范围

对于对象类型的区分除了使用操作符in还可以使用instanceof来完成。

function test(x: Date | string) {if (x instanceof Date) {console.log(x.toUTCString());} else {console.log(x.toUpperCase());}
}

使用 === 和 == 缩小类型范围

使用严格等于(===)也可以在某些特别情况下正确缩小类型范围

function example(x: string | number, y: string | boolean) {if (x === y) {// We can now call any 'string' method on 'x' or 'y'.x.toUpperCase();y.toLowerCase();} else {console.log(x); // x 是 string | numberconsole.log(y); // y 是 string | boolean}
}

在这个例子中xstringnumber的联合,而y是stringboolean的联合,当x === y的时候只可能xy都是string类型。所以在分支if (x === y) 中x和y的类型被正确识别为string类型。

我们知道在JS中宽松等于(== null)可以匹配null和undefined两种类型,当然TS也知道,所以 ==null,可以被用来识别类型。

interface Container {value: number | null | undefined;
}function multiplyValue(container: Container, factor: number) {// Remove both 'null' and 'undefined' from the type.if (container.value != null) {console.log(container.value);// Now we can safely multiply 'container.value'.container.value *= factor;}
}

即使container.value可能是null或者undefined类型,但是在分支container.value != null中,该变量类型就只可能是number类型,所以其参与算术运算并不会报错。

区分联合类型

interface Circle {kind: "circle";radius: number;
}interface Square {kind: "square";sideLength: number;
}type Shape = Circle | Square;function getArea(shape: Shape) {if (shape.kind === "circle") {return Math.PI * shape.radius ** 2;}
}

TS会通过参与联合的类型都有的属性kind来识别当前shape是Circle或者Square达到类型保护的目的。

类型谓词

上面介绍了TS对于联合类型中基础类型和对象类型的类型保护。但是这并不能覆盖全部的场景,例如上面介绍到的内容,并不能区分两个函数:

type fn1 = (arg: number) => boolean
type fn2 = (arg: string) => booleanfunction test(fn: fn1 | fn2) {return fn(1)
}

在这个例子里,我们并没有方法来识别fn是类型fn1还是类型fn2。

在前面的例子里,例如 if (typeof a === ‘string’) 这里面的变量a会被TS类型系统识别为string,如果TS将识别一个变量为某个类型的能力开放给开发者,上面的问题就会迎刃而解。这个能力就是类型谓词。

通过观察上面类型保护的规律就会发现TS总会询问:变量a是类型A吗?被识别为类型保护的操作的回答总是true或者false都是boolean值。typoef a === ‘string’或者’a’ in A或者a instanceof A,这些操作的返回值都是boolean,并且都是和特定类型作比较。

// 我就是类型谓词形成的类型保护
function isTypefn1(fn: fn1 | fn2): fn is fn1 {if (fn.name === 'fn1') return truereturn false
}
function test(fn: fn1 | fn2) {if (isTypefn1(fn)) return fn(1)else return fn('1')
}

其中 isTypefn1调用的返回值就会告诉TS入参是不是类型fn1,这样TS就可以识别变量fn的类型完成类型保护。

参考

Narrowing

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361952.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sudo apt-get install libstdc++6

sudo apt-get install libstdc6 yum install libncurses.so.5 sudo apt-get install libncurses.so.5 sudo apt-get install lib32ncurses5 apt-get update把源更新一下 使用gdb时的指令 (gbd) info line *0x08xxxx sudo apt-get install lib32z1 lib32ncurses5 lib32bz2-1.…

AngularJS快速入门指南03:表达式

AngularJS通过表达式将数据绑定到HTML。 AngularJS表达式 AngularJS表达式写在双大括号中:{{ 表达式语句 }}。 AngularJS表达式绑定数据到HTML的方式与ng-bind指令的方式相同。 AngularJS会准确地将表达式“输出”为计算的结果。 AngularJS表达式与JavaScript表达式…

零基础快速上手HarmonyOS ArkTS开发2---ArkTS开发实践

ArkTS开发实践: 接着上一次零基础快速上手HarmonyOS ArkTS开发1---运行Hello World、ArkTS开发语言介绍继续, 在上一次对于ArkTS的基础知识进行了学习,依照官方的课程计划,还有两个具体的小案例需要来实践实践: 实践出…

无状态Spring安全性第2部分:无状态身份验证

Spring Stateless Security系列的第二部分是关于以无状态方式探索身份验证的方法。 如果您错过了CSRF的第一部分,可以在这里找到。 因此,在谈论身份验证时,其全部内容就是让客户端以可验证的方式向服务器标识自己。 通常,这始于服…

TypeScript 交叉类型(intersection type)

在TS中和联合类型(union type)对应的还有交叉类型(intersection type)。 交叉类型的出现主要为了组合多个对象类型(object type),因为相对于interface,object type没法继承,那么就可以通过union type来实现混合的目的,从而实现继承…

【转】JAVA中的转义字符

JAVA中转义字符: 1.八进制转义序列:\ 1到3位5数字;范围\000~\377 \0:空字符 2.Unicode转义字符:\u 四个十六进制数字;0~65535 \u0000:空字符 3.特殊字符:就3个 \"&#xff1a…

八、VueJs 填坑日记之参数传递及内容页面的开发

我们在上一篇博文中&#xff0c;渲染出来了一个列表&#xff0c;并在列表中使用了router-link标签&#xff0c;标签内的&#xff1a;to就是链接地址&#xff0c;昨天咱们是<router-link :to"/content/ i.id">这样写的&#xff0c;今天我们来完成内容页面的渲染…

为Kindeditor控件添加图片自动上传功能

Kindeditor是一款功能强大的开源在线HTML编辑器&#xff0c;支持所见即所得的编辑效果。它使用JavaScript编写&#xff0c;可以无缝地与多个不同的语言环境进行集成&#xff0c;如.NET、PHP、ASP、Java等。官方网站可以查看这里&#xff1a;http://kindeditor.net/index.php Ki…

TypeScript类型推论(Type Inference)

要完全理解类型推论需要完整理解类型上下文&#xff0c;并且理解TS对于是否可以使用类型推论是基于静态分析完成的。 上下文类型应用在许多地方。常见的例子包括函数调用的参数&#xff0c;赋值的右手端位置&#xff0c;类型断言&#xff0c;对象和数组的成员&#xff0c;和返回…

4个万无一失的技巧让您开始使用JBoss BRMS 6.0.3

上周&#xff0c;红帽发布了标记为6.0.3的JBoss BRMS的下一版本&#xff0c;已订阅的用户可以在其客户门户中使用。 如果您对该版本的新增功能感到好奇&#xff0c;请在客户门户网站上在线查看版本说明和其余文档 。 我们正在寻找一些简单的方法来开始使用此新版本&#xff0…

统一命名规则

1. #define 保护 所有头文件都应该使用 #define 防止头文件被多重包含, 命名格式当是:<PROJECT>_<PATH>_<FILE>_H_ 项目 SkinTK中的头文件 SkinTK/SkinTK/targetver.h 可按如下方式保护: #ifndef SKINTK_SKINTK_TARGETVER_H_ #define SKINTK_SKINTK_TARGETVE…

中国移动MM7 API用户手册(七)

4.4 VASP接收状态报告&#xff08;上行业务&#xff09;当VASP在发送MM7SubmitReq给MMSC时设置需要发送状态报告的请求为true时&#xff0c;MMSC在收到MM7SubmitReq后&#xff0c;会发送状态报告给VASP&#xff0c;此时VASP可以进行接收。接收方式和接收传送消息一样&#xff…

如何仅通过CSS实现多行文本超长自动省略号

在CSS中&#xff0c;我们可以通过下面的样式实现DIV元素中文本超长后自动截断并以省略号结尾&#xff1a; overflow: hidden;word-break: normal;text-overflow: ellipsis; text-overflow: ellipsis是实现文本截断后以省略号结尾的关键样式&#xff0c;但问题是如果添加该样式则…

带有Angular JS的Java EE 7 – CRUD,REST,验证–第2部分

这是Angular JS承诺的Java EE 7的后续版本–第1部分 。 花了比我预期更长的时间&#xff08;找到时间来准备代码和博客文章&#xff09;&#xff0c;但是终于到了&#xff01; 应用程序 第1部分中的原始应用程序只是带有分页的简单列表&#xff0c;以及提供列表数据的REST服务…

Chrome不显示OPTIONS请求的解决方法2021版chrome90

在chrome90上之前展示跨域请求预检请求的方法失效了&#xff1a; 在chrome地址栏总输入 chrome://flags/#out-of-blink-cors 将其设置为Disabled后重启浏览器 在chrome://flags找不到选项out-of-blink-cors。取而代之的是chrome将预检请求放到了控制台网络面板的 OTHER 面板中。…

安装CentOs 5.5后无法显中文(中文乱码)

症状&#xff1a;在使用CentOS 系统时&#xff0c;安装的时候可能你会遇到英文的CentOS系统&#xff0c;在这中情况下安装CentOS系统时是默认安装&#xff08;即英文&#xff09;。安装完毕后&#xff0c;上网出现的却是中文乱码。 解决方法&#xff1a; 到CentOs资源网站上去找…

粗读《构建之法》后的思考和收获

利用出差的空挡&#xff0c;快速阅读了一下邹欣老师的《构建之法》一书。对我校软件工程的教学改革确实有很多值得参考的地方&#xff0c;强调实践环节和社会实际工作流程的结合&#xff0c;而不是为了实验而实验。 在阅读过程也有一些问题。 问题1&#xff1a;MSF中强调人员的…

SVG实现波浪效果

SVG实现波浪效果 svg path&#xff1a;C 贝塞尔曲线绘制波浪形状 A 绘制圆弧形 svg animate&#xff1a;制作波浪动画&#xff0c;为了波浪动画效果自然&#xff0c;设置values关键点       attributeName&#xff1a;变化属性名 dur&#xff1a;动画时间 repeatCount&a…

允许同站跨域Nginx配置方案

基于目前前后端分离的趋势和微前端解决方案&#xff0c;并且很多web服务部署在Nginx服务器上&#xff0c;那么因为前后端分离导致的跨域问题需要迫切得到解决。因为是否允许跨域的因素有协议、域名、端口&#xff0c;只要有一个不一致就算跨域。大部分需求要求一个一级域名下所…

使用WildFly 8在Java EE7中自举Apache Camel

从Camel版本2.10开始&#xff0c;支持CDI&#xff08;JSR-299&#xff09;和DI&#xff08;JSR-330&#xff09;。 这为在Java EE容器中以及独立Java SE或CDI容器中开发和部署Apache Camel项目提供了新的机会。 是时候尝试一下并熟悉它了。 骆驼到底是什么&#xff1f; 骆驼是…