TS条件类型
类似于各种计算出来的类型,基于extends,也常常带上泛型
TS也提供了很多很多内置条件类型
type ResStatusMessage<T> = T extends 200 | 201 | 204 | 206 ? "success" : "fail";
type IMessage = ResStatusMessage<300>; // type IMessage = "fail"
type Conditional<T, U> = T extends U ? true : false;
type R1 = Conditional<"jiangwen", string>;
type R2 = Conditional<"jiangwen", number>; // 泛型在条件类型中广泛被应用
type FormatReturnValue<T> = T extends string ? string : T extends number ? number : never;
function sum<T extends string | number>(a: T, b: T): FormatReturnValue<T> {
return a + (b as any); // 泛型之间不能做运算;
}
let r = sum(1, 2); // string & number
分发机制引发的问题
联合类型 通过泛型传入 且 直接作为裸类型使用时,会触发分发机制
interface Fish { name: "鱼"; }
interface Water { type: "水"; }
interface Bird { name: "鸟"; }
interface Sky { type: "太空"; }
type SelectType<T> = T extends Fish ? Water : Sky;
// 两种类型分别传入,并返回结果
// type T7 = Water | Sky
type T7 = SelectType<Bird | Fish>;
// 非泛型使用,未触发分发
// type T8 = Sky
type T8 = Bird | Fish extends Fish ? Water : Sky;
// 经过了运算,未触发分发
// type T9 = Sky
type SelectType2<T> = T[] extends Fish[] ? Water : Sky;
type T9 = SelectType<Bird | Fish>;
分发机制 会在条件类型内引发 子类判断异常的问题
由于分发机制,
T7中的1 2 3 分别和 1 | 2 做了比较,得到了 true | false 的type,也就是boolean
而理论上,我们希望的是 type 1 | 2 | 3 与 type 1 | 2,做比较,得到 false
type UnionAssets1<T, U> = T extends U ? true : false;
type T7 = UnionAssets1<1 | 2 | 3, 1 | 2>; // boolean
// 解决方案
type NoDistribute<T> = T & {}; // 避免分发机制
type UnionAssets<T, U> = NoDistribute<T> extends U ? true : false;
type T8 = UnionAssets<1 | 2, 1 | 2 | 3>; // true
type T9 = UnionAssets<1 | 2 | 3, 1 | 2>; // false
any也会有分发问题
never也会有分发问题, 但只在泛型传递的时候会返回never, 不分发就正常
type T10 = any extends "123" ? true : false; // boolean
type isNever<T> = T extends never ? true : false;
type T11 = isNever<never>; // never
type T12 = never extends never ? true : false; // true
判断两个类型完全相等
T extends U && U extends T,
Success 相等时返回的类型
Fail 不相等时 返回的类型
type NoDistribute<T> = T & {}; // 避免分发机制
type IsEqual<T, U, Success, Fail> =
NoDistribute<T> extends U ? NoDistribute<U> extends T ? Success : Fail : Fail;
type T10 = IsEqual<1 | 2, 1 | 2, true, false>;
// type T10 = true
内置条件类型 Extract Exclude NonNullable |
内置条件类型 Extract Exclude NonNullable 本质上 就是分发.
Extract 交集
// string | number
type ExtractResult = Extract<string | number | boolean, string | number>;
其本质如下,实际上是产生了分发,得到的结果
type Extract<T, U> = T extends U ? T : never;
// T中的 成员会依次 与 U比较
// 上例得到的结果如下: string | number | never
Exclude 差集
// boolean
type ExcludeResult = Exclude<string | number | boolean, string | number>;
其本质如下,实际上是产生了分发,得到的结果
type Exclude<T, U> = T extends U ? never : T;
// T中的 成员会依次 与 U比较
// 上例得到的结果如下: never | never | boolean
NonNullable 去掉联合类中的null
let ele = document.getElementById("root");
type EleElement = NonNullable<typeof ele>;
其本质如下,实际上是产生了分发,得到的结果
type NonNullable<T> = T & {};
infer 获取T中指定位置的派生类型
infer 用在条件类型中,获取T中指定位置的派生类型
补充一个知识点,约束一个类型为函数
type Func<T> = T extends (...args: any[]) => any ? true : never
type Func1<T> = T extends Function ? true : never
function a() { }
type f = Func<typeof a>
ReturnType 内置类型
infer 实现原生 内置条件类型 ReturnType
获取函数的返回类型
function getUser(a: number, b: number) {
return { name: 'zf', age: 10 }
}
// 首先得约束传入的T是函数类型
type ReturnType<T extends (...args: any[]) => any> =
T extends (...args: any) => infer R ? R : never
type MyReturn = ReturnType<typeof getUser>
// type MyReturn = {
// name: string;
// age: number;
// }
type TailToHead<T extends any[]> =
ST extends [...infer C, infer B] ? [B, ...C] : any;
type x = TailToHead<["jw", 30, 40, 50, "回龙观"]>;
// ["回龙观","jw",30,40,50]
Parameters 内置类型
获取函数的参数类型
type Parameters<T> = T extends (...args: infer R) => any ? R : any;
type MyParams = Parameters<typeof getUser>;
ConstructorParameters 内置类型
获取类的构造函数的参数类型
class Person {
constructor(name: string, age: number) { }
}
type ConstructorParameters<T> = T extends { new(...args: infer R): any } ? R : never
type MyConstructor = ConstructorParameters<typeof Person>
InstanceType 内置类型
获取类的实例类型
class Person {
constructor(name: string, age: number) { }
}
type InstanceType<T> = T extends { new(...args: any): infer R } ? R : any
type MyInstance = InstanceType<typeof Person>
很显然,Person的实例类型就是Person
将数组类型转化为联合类型
有点像分发并返回,但不是分发
type ElementOf<T> = T extends Array<infer E> ? E : never;
type TupleToUnion = ElementOf<[string, number, boolean]>;
infer获取泛型类型
type PromiseV<T> = T extends Promise<infer V> ? V : any;
type PromiseReturnValue = PromiseV<Promise<number>>; // number
// 甚至能递归,拿到不是Promise类型为止
type PromiseV<T> = T extends Promise<infer V> ? PromiseV<V> : T;
type PromiseReturnValue = PromiseV<Promise<Promise<number>>>; // number
将两个函数的参数转化为交叉类型s
type T1 = { name: string };
type T2 = { age: number };
type ToIntersection<T> = T extends ([(x: infer U) => any, (x: infer U) => any]) ? U : never;
type t3 = ToIntersection<[(x:T1)=>any,(x:T2)=>any]>
其他
any和unknown互为子类型,且不是其他任何类型的子类型