本文主要记录书中关于TypeScript类型收缩的内容

本文主要内容如下

  1. 类型收缩的一些方法
    1. 条件判断
    2. 抛错误
    3. instanceof 和 in 属性检查
    4. “标签联合”或“可辨识联合”
  2. 类型收缩的失效示例
  3. 自定义类型保护
  4. 总结

类型收缩的方法

条件判断

const el = document.getElementById("foo");
if (el) {
el; // 类型是HTMLElement
} else {
el; // 类型是 null
}

如果 el 是 null,那么第一个分支的代码就不会执行,所以 TypeScript 能够在这个代码块中推断出一个更容易处理的类型。

抛错误

const el = document.getElementById("foo");
if(!el) throw new Error('未找到元素');
el.innerHTML = 'Hello World'; //HTMLElement

instanceof 和 in 属性检查

function contains (text:string,search:string|RegExp) {
if(search instanceof RegExp) {
// 类型是Regexp
return !!search.test(text);
} // 类型是 string
return text.includes(search);
}
interface A {a:number}
interface A {a:number}
interface B {b:number} function pickAB(ab:A|B) {
if('a' in ab) {
ab // 类型是A
} else {
ab // 类型是B
} ab // 类型是A|B
}

ps:原文中提到一个示例如下:

function contains(text:string,terms:string|string[]) {
const termList = Array.isArray(terms) ? terms : [terms];
termList // 类型是 string[]
}

这是通过内置函数来完成类型收缩的

“标签联合”或“可辨识联合”

interface UploadEvent {type:'upload',filename:string;content:string}
interface DownloadEvent {type:'download',filename:string;}
type AppEvent = UploadEvent|DownloadEvent; function handleEvent(e:AppEvent) {
switch(e.type) {
case "upload":
e // 类型是UploadEvent
break;
case 'download':
e // 类型是Download
break;
}
}

帮助检查器收缩范围的常见方法是给他们加上一个明确的“标签”,这种模式称为 “标签联合” 或 “可辨识联合”,它在TypeScript中很常见。

类型收缩的失效示例

const el = document.querySelector('#foo');
if(typeof el === 'object') {
el; // Element | null
}

在 JavaScript 中,typeof null 也是 "object",所以这个类型收缩是不成立的,类似的还有如下这样:

function foo(x?:number|string|null) {
if(!x) {
x // string | number | null | undefined
}
}

自定义类型保护

function isInputElement(el:HTMLElement): el is HTMLInputElement {
return 'value' in el;
} function getElementContent(el:HTMLElement) {
if(isInputElement(el)) {
el // 类型是 HTMLInputElement;
return el.value;
}
return el.textContent; // 类型是 HTMLElement
}

这就是所谓的“自定义类型保护”,el is HTMLInputElement 作为返回值,如果函数返回true,它可以收缩类型的参数。

跨数组或对象的类型收缩

const students = ["小明", "小红", "小柔"];

// const people = ["小红", "小柔"].map((who) => students.find((n) => n === who)); //类型 (string | undefined)[]

// 如果用filter过滤undefined,TypeScript 无法跟上filter的逻辑

// const people = ["小红", "小柔"]
// .map((who) => students.find((n) => n === who))
// .filter((who) => who != undefined);
// 类型仍然是 (string | undefined)[] // 但是使用类型保护就可以 function isDefined<T>(x:T|undefined):x is T {
return x != undefined;
} const people = ["小红", "小柔"]
.map((who) => students.find((n) => n === who))
.filter(isDefined);
// 类型是 string[]

总结

  • 了解TypeScript如何根据条件和其他类型的控制流来收缩类型。
  • 使用标记/可辨识类型或者自定义类型保护来收缩类型。

《Effective TypeScript》条款22 - 类型收缩的更多相关文章

  1. [More Effective C++]条款22有关返回值优化的验证结果

    (这里的验证结果是针对返回值优化的,其实和条款22本身所说的,考虑以操作符复合形式(op=)取代其独身形式(op),关系不大.书生注) 在[More Effective C++]条款22的最后,在返回 ...

  2. Effective C++ -----条款22:将成员变量声明为private

    切记将成员变量声明为private.这可赋予客户访问数据的一致性.可细微划分访问控制.允诺约束条件获得保证,并提供class作者以充分的实现弹性. protected并不比public更具有封装性.

  3. More Effective C++ 条款0,1

    More Effective C++ 条款0,1 条款0 关于编译器 不同的编译器支持C++的特性能力不同.有些编译器不支持bool类型,此时可用 enum bool{false, true};枚举类 ...

  4. TypeScript完全解读(26课时)_11.TypeScript完全解读-类型推论和兼容性

    11.TypeScript完全解读-类型推论和兼容性 在一些时候省略指令,ts会帮我们推断出省略的类型的地方适合的类型,通过学习ts的类型推论了解ts的推论规则 类型兼容性就是为了适应js灵活的特点, ...

  5. TypeScript Type Compatibility(类型兼容)

    TypeScript中的类型兼容是基于结构归类的.在普通分类的相比之下,结构归类是一种纯粹用于将其成员的类型进行关联的方法.思考下面的代码: interface Named { name: strin ...

  6. TypeScript Type Innference(类型推断)

    在这一节,我们将介绍TypeScript中的类型推断.我们将会讨论类型推断需要在何处用到以及如何推断. 基础 在TypeScript中,在几个没有明确指定类型注释的地方将会使用类型推断来提供类型信息. ...

  7. EC读书笔记系列之12:条款22、23、24

    条款22 将成员变量声明为private 记住: ★切记将成员变量声明为private.这可赋予客户访问数据的一致性.可细微划分访问控制.允诺约束条件获得保证,并提供class作者以充分的实现弹性. ...

  8. TypeScript 之 基础类型、高级类型

    基础类型:https://m.runoob.com/manual/gitbook/TypeScript/_book/doc/handbook/Basic%20Types.html 高级类型:https ...

  9. 聊聊 TypeScript 中的类型保护

    聊聊 TypeScript 中的类型保护 在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况: interface Bird { // 独有方法 fly(); // 共有方法 lay ...

随机推荐

  1. 问题--ImportError: DLL load failed: 找不到指定的模块

    今天在运行别人的项目时出现了问题: ImportError: DLL load failed: 找不到指定的模块. 解决方法: 卸载后重新安装. 详情参考: Python报错:ImportError: ...

  2. Rainbond通过插件整合ELK/EFK,实现日志收集

    前言 ELK 是三个开源项目的首字母缩写:Elasticsearch.Logstash 和 Kibana.但后来出现的 FileBeat 可以完全替代 Logstash的数据收集功能,也比较轻量级.本 ...

  3. 13 个 C# 10 特性

    原文链接:https://blog.okyrylchuk.dev 原文作者:Oleg Kyrylchuk 译: 等天黑 常量的内插字符串 C# 10 允许使用在常量字符串初始化中使用插值, 如下 co ...

  4. Learning a Similarity Metric Discriminatively, with Application to Face Verification

    目录 概 主要内容 genuine 和 impostor 文1 文2 Chopra S, Hadsell R, Lecun Y, et al. Learning a similarity metric ...

  5. Mysql客户端的安装

    Mysql数据库(简称)属于C/S架构,正常工作中一般都会提供服务端,我们只需要安装客户端进行查询修改数据等操作即可. 正常工作中不管是测试人员或者开发人员,一般数据库的管理员(测试负责人或者开发负责 ...

  6. Android 悬浮窗 System Alert Window

    悬浮窗能显示在其他应用上方.桌面系统例如Windows,macOS,Ubuntu,打开的程序能以窗口形式显示在屏幕上. 受限于屏幕大小,安卓系统中主要使用多任务切换的方式和分屏的方式.视频播放,视频对 ...

  7. Linux系统管理学习实训任务书

    1.<Linux系统管理实训任务一之搭建实验基础环境> https://www.toutiao.com/i6763578305091207694/ 2.<Linux系统管理实训任务一 ...

  8. x86-3-段式管理(segmentation)

    x86-3-段式管理(segmentation) 3.1 段式管理概述: 从8086CPU开始,为了让程序在内存中能自由浮动而又不影响它的正常执行,CPU将内存划分成逻辑上的段来给程序使用. x86继 ...

  9. 【Java】枚举类

    文章目录 枚举类的使用 如何定义枚举类 方式一:jdk5.0之前,自定义枚举类 方式二:jdk5.0,可以使用enum关键字定义枚举类 Enum类的主要方法 toString() values() v ...

  10. pycharm创建脚本头文件模板

    代码头文件信息可以包括:python 解析器的位置.字符集.作者信息.创建脚本时间等,pycharm工具创建头部信息模板操作步骤如下: 设置头文件:文件-->设置-->编辑器-->文 ...