标签
note
字数
803 字
阅读时间
4 分钟
extends
typescript 2.8 引入了条件类型关键字: extends,长这个样子:
java
T extends U ? X : Y
复制代码点像三元运算符: condition ? result(1) : result(2),用大白话可以表示为:
如果
T包含的类型 是U包含的类型的 ' 子集 ',那么取结果X,否则取结果Y。
再举几个 ts 预定义条件类型的例子,加深理解:
typescript
type NonNullable<T> = T extends null | undefined ? never : T;
// 如果泛型参数 T 为 null 或 undefined,那么取 never,否则直接返回T。
let demo1: NonNullable<number>; // => number
let demo2: NonNullable<string>; // => string
let demo3: NonNullable<undefined | null>; // => never
复制代码分配式 extends
java
T extends U ? X : Y其实就是当上面的 T 为联合类型的时候,会进行拆分,有点类似数学中的分解因式:
(a + b) * c => ac + bc
再举个官网的例子:
perl
type Diff<T, U> = T extends U ? never : T; // 找出T的差集
type Filter<T, U> = T extends U ? T : never; // 找出交集
type T30 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // => "b" | "d"
// <"a" | "b" | "c" | "d", "a" | "c" | "f">
// 相当于
// <'a', "a" | "c" | "f"> |
// <'b', "a" | "c" | "f"> |
// <'c', "a" | "c" | "f"> |
// <'d', "a" | "c" | "f">
type T31 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // => "a" | "c"
// <"a" | "b" | "c" | "d", "a" | "c" | "f"> 同上
let demo1: Diff<number, string>; // => numberinfer
在 extends 语句中,还支持 infer 关键字,可以推断一个类型变量,高效的对类型进行模式匹配。但是,这个类型变量只能在 true 的分支中使用。
typescript
// 内置 ReturnType
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;不知道初学 ts 的朋友们看完这个介绍是不是一脸懵逼,反正之前我是...
其实理解之后很简单,这里直接说下我的理解,应该还算简单易懂:
infer X 就相当于声明了一个变量,这个变量随后可以使用,是不是有点像 for 循环里面的声明语句?
css
for (let i = 0, len = arr.length; i < len; i++) {
// do something
}不同的是,infer X 的这个位置本应该有一个写死的类型变量,只不过用 infer R 替换了,更灵活。
需要注意的是 infer 声明的这个变量只能在 true 分支中使用
例子一
typescript
// 解读: 如果泛型变量T是 () => infer R的`子集`,那么返回 通过infer获取到的函数返回值,否则返回boolean类型
type Func<T> = T extends () => infer R ? R : boolean;
let func1: Func<number>; // => boolean
let func2: Func<''>; // => boolean
let func3: Func<() => Promise<number>>; // => Promise<number>
复制代码例子二
typescript
// 同上,但当a、b为不同类型的时候,返回不同类型的联合类型
type Obj<T> = T extends {a: infer VType, b: infer VType} ? VType : number;
let obj1: Obj<string>; // => number
let obj2: Obj<true>; // => number
let obj3: Obj<{a: number, b: number}>; // => number
let obj4: Obj<{a: number, b: () => void}>; // => number | () => void参考
白话typescript中的【extends】和【infer】 - 掘金