TS条件类型


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互为子类型,且不是其他任何类型的子类型


文章作者: 罗紫宇
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗紫宇 !
  目录