TypeScript 学习笔记 — 交叉类型、条件类型和条件分发(八)
交叉类型
交叉类型(交集)会把多个类型变成一个类型,相当于 & 按位与操作 (都要满足才可以),生成的交叉类型 是 A B 的子类 ,内部的嵌套类型也会做交叉类型。
联合类型(并集)相当于| 按位或,满足其中一个就可以。
interface Person1 {
handsome: string;
address: {
n: string;
};
}
interface Person2 {
high: string;
address: {
n: number;
};
}
type Person = Person1 & Person2; // 交叉类型
type a = string | number; // 联合类型
type Temp = Person["address"]["n"]; // type Temp = never
合并两个对象,相同的属性类型会变成 never, 交叉后的结果涵盖所有内容
function mixin<T, U>(a: T, b: U): T & U {
return { ...a, ...b };
}
type Compute<T> = { [P in keyof T]: T[P] };
let r = mixin({ a: 1, b: 2 }, { c: 3, b: "2" });
type x = Compute<r>; // type x = { a: number; b: never; c: number;}
条件类型
泛型 extends 约束经常和条件类型一起 使用,条件类型的格式可以看成是三元表达式:
1. 直接传入判断的条件
// 联合类型而言子类型是其中的任何一个
type ResStatusMessage<T> = T extends 200 | 201 | 204 | 206 ? "success" : "fail";
type IMessage1 = ResStatusMessage<300>; // type IMessage1 = "fail"
type IMessage2 = ResStatusMessage<200>; // type IMessage1 = "success"
2. 把条件当成泛型传入
// 泛型在条件类型中广泛被应用
type Conditional<T, U> = T extends U ? true : false;
type R1 = Conditional<"yya", string>; // type R1 = true
type R2 = Conditional<"yya", number>; // type R2 = false
3. 多重条件判断
简单的案例解析:1 + 2 = 3,添加类型
// 如果是字符串 返回字符串, 如果是number返回number 两者都不是返回nerver
type FromatReturnValue<T> = T extends string ? string : T extends number ? number : never;
function sum<T extends string | number>(a: T, b: T): FromatReturnValue<T> {
return a + (b as any); // 泛型之间不能做运算;
}
let r1 = sum(1, 2); // number
let r2 = sum("1", "2"); // string
4. 判断接口中的类型
interface Fish {
name: "鱼";
}
interface Water {
type: "水";
}
interface Bird {
name: "鸟";
}
interface Sky {
type: "太空";
}
type SelectType<T> = T extends Fish ? Water : Sky;
type R3 = SelectType<Bird>; // type R3 = Sky
extends 父子关系(类型等级)
- never 类型是字面量类型的子类型(never 底端类型 最底层的)
- 字面量类型是基础类型的子类型
- 基础类型是包装类型的子类型(所有包装类型的上一层都是 Object)
- 所有类型都是 any 和 unknown 的子类型
- 其他类型 null、undefined、void
- 子类型可以赋予给父类型
// 1. never是字面量类型的子类型
type T1 = never extends "123" ? true : false;
let a: number = (function (): never {
throw new Error();
})();
// 2. 字面量类型 是基础类型的子类型
type T2 = 123 extends number ? true : false;
type T3 = "abc" extends string ? true : false;
// 3. 基础类型是包装类型的子类型
type T4 = string extends String ? true : false;
type T5 = String extends Object ? true : false;
// 4. 所含有类型都是 any 和 unknown 的子类型
type T6 = any extends any ? true : false; // type T6 = true
type T7 = any extends unknown ? true : false; // type T7 = true
type T8 = any extends 1 ? true : false; // type T8 = boolean any 可以看成 1 + 其它类型(内置有分发的机制)直接取最终的联合类型
type T9 = any extends 1 ? 1 : 2; // type T9 = 1 | 2
type T10 = unknown extends 1 ? true : false; // type T10= false
// 5. 其他类型 null、undefined、void
type T11 = null extends null ? true : false;
type T12 = undefined extends undefined ? true : false;
type T13 = undefined extends void ? true : false;
条件分发机制
分发机制触发条件:
- 通过泛型传入的方式来比较时会出现分发
- 类型是联合类型
- 类型需要完全的裸露出来(裸类型)
简单的案例解析: 类型(联合类型)的比较 (分发)
interface Fish {
name: "鱼";
}
interface Water {
type: "水";
}
interface Bird {
name: "鸟";
}
interface Sky {
type: "太空";
}
type SelectType<T> = T extends Fish ? Water : Sky;
// 这里会用每一项依次进行分发,最终采用联合类型作为结果,等价于:
/** 对比过程
* Bird -> Fish -> Sky
* Fish -> Fish -> Water
* Sky | Water
*/
type T1 = SelectType<Bird | Fish>; // type T1 = Water | Sky
// 如果上述泛型换一种写法,使其并非裸类型,结果会是怎么样呢?
type SelectType_2<T> = T[] extends Fish[] ? Water : Sky; // 外面包一层,使其并非裸类型
type SelectType_3<T> = T & {} extends Fish ? Water : Sky; // 外面包一层,使其并非裸类型
type T2 = SelectType_2<Bird | Fish>; // type T2 = Sky
type T3 = SelectType_3<Bird | Fish>; // type T3 = Sky
实际开发中如何避免?
<T,U>判断 T 是不是 U 的子类型?
<T,U>判断 T 是不是 U 的子类型:<1|2, 1|2|3> <1|2|3, 1|2>,实际开发时,由于分发机制返回 boolean,并没有实际意义:
// 是泛型,是联合类型,是裸类型,会触发分发机制
type UnionAssets<T, U> = T extends U ? true : false;
type T1 = UnionAssets<1 | 2, 1 | 2 | 3>; // true
type T2 = UnionAssets<1 | 2 | 3, 1 | 2>; // true | true | false -> boolean
// 包了一层,并非裸类型,表示不分发
type NoDistrubte<T> = T & {};
type UnionAssets_1<T, U> = NoDistrubte<T> extends U ? true : false;
type T3 = UnionAssets_1<1 | 2, 1 | 2 | 3>; // true
type T4 = UnionAssets_1<1 | 2 | 3, 1 | 2>; // false
判断两个类型完全相等?
通过正反 extends,判断自身与其他类型是否相等
// 包了一层,并非裸类型,表示不分发
type NoDistrubte<T> = T & {};
type IsEqual<T, U, Success, Fail> = NoDistrubte<T> extends U ? (NoDistrubte<U> extends T ? Success : Fail) : Fail;
type T1 = IsEqual<1 | 2, 2 | 1, true, false>; // true
type T2 = IsEqual<1 | 2 | 3, 2 | 1, true, false>; // false
never 分发问题
- any 默认分发
- never 默认只有在通过泛型传递时 会返回 never,不分发就正常
type T1 = any extends any ? true : false; // true
type T2 = any extends 1 ? true : false; // boolean 可以看成 1 + 其它类型,直接取最终的联合类型
type T3 = any extends 1 ? 1 : 2; // 1 | 2
type NoDistrubte<T> = T & {};
type isNever<T> = T extends never ? true : false;
type isNever_2<T> = NoDistrubte<T> extends never ? true : false;
type T4 = isNever<never>; // never
type T5 = isNever_2<never>; // true
内置的条件类型
1.Exclude 排除类型(差集)
type Exclude<T, U> = T extends U ? never : T; // 自己实现 never | never | boolean
type ExcludeResult = Exclude<string | number | boolean, string | number>;
2.Extract 抽取类型(交集)
type Extract<T, U> = T extends U ? T : never; // 自己实现 string | number | never
type ExtractResult = Extract<string | number | boolean, string | number>;
3.NoNullable 非空检测
如果类型中包含 null ,就去掉
let ele = document.getElementById("root");
// type NonNullable<T> = T & {}; // 源码写法
type NonNullable<T> = T extends null | undefined ? never : T; // 自己实现
type EleElement = NonNullable<typeof ele>;
4. Complement 自己实现 (补集)
含义就是互补的 = 差集 + 子类的关系
type Complement<T, U extends T> = T extends U ? never : T; // never | number | boolean
type ComplementResult = Complement<string | number | boolean, string>;
TypeScript 学习笔记 — 交叉类型、条件类型和条件分发(八)的更多相关文章
- TypeScript 学习笔记 — 函数中的类型(四)
目录 函数的两种声明方式 可选参数 默认参数 剩余参数 函数的重载 this 的类型 对于函数主要关心的是:函数的入参类型 和 函数的返回值类型 函数的两种声明方式 通过 function 关键字来进 ...
- javascript学习笔记(四) Number 数字类型
数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数 toExponential() 方法 用科学 ...
- Typescript 学习笔记七:泛型
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记六:接口
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记五:类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记二:数据类型
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记三:函数
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记一:介绍、安装、编译
前言 整理了一下 Typescript 的学习笔记,方便后期遗忘某个知识点的时候,快速回忆. 为了避免凌乱,用 gitbook 结合 marketdown 整理的. github地址是:ts-gitb ...
- Typescript 学习笔记四:回忆ES5 中的类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- TypeScript学习笔记(八):1.5版本之后的模块和命名空间
我之前有写过TS1.5版本之前的“模块”的笔记:TypeScript学习笔记(七):模块 但是TS这里的模块和在ECMAScript 2015里的模块(即JS原生支持了模块的概念)概率出现了混淆,所以 ...
随机推荐
- windows下使用winget快速安装nvm
前置条件: 操作系统 >= win10 安装 首先使用winget搜索nvm包 winget search nvm #搜索结果如下图 安装nvm winget install CoreyButl ...
- vue2.0,把vform666、workFlow开源组件集成到vue-admin-template框架上心得体会
以上三个都是vue2版本的开源项目,有的已经有vue3版本了,我把他们集成到一起,是出于练习的目的,也是消磨时间. vue-admin-template是一个很基础简洁的后台管理系统框架:vform6 ...
- AI绘图之Midjourney初体验
Midjourney (MJ) 使用笔记 最近尝试了 Midjourney 绘图,简单记录下使用流程. 注册及登陆 首先是账号注册和登陆,基本上就是一路下一步,唯一需要注意的是加入MJ频道,具体流程为 ...
- C#中位枚举(Flags)
在日常的开发工作当中,位枚举可能会被经常使用,如星期多选.租期多选等等,我们可以将多选字段做或运算,然后保存到数据库表的字段中,如 1 | 2 = 3(0001 | 0010 = 0011 = 3). ...
- 计算巢AppFlow-如何在钉钉群实现智能答疑
随着大模型能力越来越强大,利用大语言模型进行智能答疑已经成为了一个非常普遍和常见的场景.然而,各个产品或业务方要能够准确有效地进行答疑,仅依靠大模型的通用能力是远远不够的,这时候利用私有领域FAQ文档 ...
- 使用 TiDB Vector 搭建 RAG 应用 - TiDB 文档问答小助手
本文首发至TiDB社区专栏:https://tidb.net/blog/7a8862d5 前言 继上一次<TiDB Vector抢先体验之用TiDB实现以图搜图>后,就迫不及待的想做一些更 ...
- (八十八)c#Winform自定义控件-转子
官网 http://www.hzhcontrols.com/ 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kw ...
- 后端给前端rtmp和flv直播 播放方法
const suffixal = this.videoObj.videoServer .split('?')[0] .split('.') .pop() var router = this.$rout ...
- SCOI 回旋退役记
02.21 day -2 开始写了,期望这不是真的退役记吧.但是不是的概率好小-- 这几天一直考试,怎么说呢,到差不差的,也就那个样子. 归根结底,菜是原罪,和那些大佬相比我真的很很很菜啊.当时看 c ...
- 关于朋友圈出现的小米新店广告骗局(非法获取个人消息)木马通过广东政务服务网(tyrz.gd.gov.cn)的url漏洞显示
前两天在朋友圈突然看到有发 小米新店开业 送千台扫地机器人的 广告,出于天上不会掉馅饼到我身上的原则 我选择忽略了,但是没多久 看到他又晒了个物流订单,于是还是点开看了一下,发现微信打开的网站还蛮正规 ...