Z
ZHANK
高级类型

条件类型与 infer

理解条件类型语法、infer 关键字提取类型

条件类型与 infer

条件类型是 TypeScript 类型系统的"if-else",infer 则能从中提取类型。

学完本章你将: 掌握条件类型语法、infer、分布式条件类型。


条件类型语法

typescript
// 基本语法:T extends U ? X : Y
type IsArray<T> = T extends unknown[] ? true : false;

type A = IsArray<string[]>; // true
type B = IsArray<number>;   // false

// 嵌套条件
type TypeName<T> =
    T extends string ? "string" :
    T extends number ? "number" :
    T extends boolean ? "boolean" :
    T extends Function ? "function" :
    "object";

分布式条件类型

typescript
// 当 T 是联合类型时,条件类型分布到每个成员
type ToArray<T> = T extends unknown ? T[] : never;

// 注意:分布式
type R1 = ToArray<string | number>; // string[] | number[]
// 等价于:ToArray<string> | ToArray<number>

// 阻止分布式:用元组包裹
type ToArrayNonDist<T> = [T] extends [unknown] ? T[] : never;
type R2 = ToArrayNonDist<string | number>; // (string | number)[]

infer 提取

typescript
// 提取数组元素
type Flatten<T> = T extends (infer Item)[] ? Item : T;
type F1 = Flatten<string[]>; // string
type F2 = Flatten<number>;   // number

// 提取 Promise 值
type Unwrap<T> = T extends Promise<infer V> ? Unwrap<V> : T;
type U1 = Unwrap<Promise<Promise<number>>>; // number(递归)

// 提取函数参数第一个
type FirstArg<T> = T extends (first: infer F, ...rest: infer _) => unknown ? F : never;
type FA = FirstArg<(a: string, b: number) => void>; // string

实战:深度 Readonly

typescript
type DeepReadonly<T> = {
    readonly [K in keyof T]: T[K] extends object
        ? T[K] extends Function
            ? T[K]
            : DeepReadonly<T[K]>
        : T[K];
};

interface Config {
    server: { host: string; port: number };
    timeout: number;
}
type ReadonlyConfig = DeepReadonly<Config>;
// { readonly server: { readonly host: string; readonly port: number }; readonly timeout: number }