TypeScript 类型运算符之 infer

158 阅读3分钟

infer关键字是类型推断的强大工具,它主要用于泛型约束中,允许从表达式中推断出类型。infer的关键在于它能够捕获和利用类型信息,而不仅仅是匹配类型结构

/*
1.  T1 和 T2:
    -   T1 定义了一个字符串字面量类型,格式为 `key=value`。
    -   T2 定义了一个联合类型,包含 `'key'` 或 `'value'`。
    -   `T3<S>` 是一个条件类型,它检查 `S` 是否符合模式 `${infer A}=${infer B}`。如果符合,它将返回 `A` 或 `B` 的联合类型,否则返回 `never`。
-   `T4` 应用 `T3` 到 `T1`,因此 `T4` 将是 `'key' | 'value'`。
*/
type T1 = 'key=value'
type T2 = 'key' | 'value'
type T3<S> = S extends `${infer A}=${infer B}` ? A | B : never
type T4 = T3<T1>

/*
1.  T5 和 T6:
    -   `T5` 定义了一个包含多个键值对的字符串字面量类型,格式为 `'a=1&b=2&c=3'`。
    -   `T6<S>` 是一个递归条件类型,它检查 `S` 是否符合模式 `${infer A}&${infer B}`。如果是,它将返回 `A` 或 `T6<B>` 的联合类型,否则返回 `S`。
    -   `T7` 应用 `T6` 到 `T5`,因此 `T7` 将是 `'a' | 'b' | 'c'`。
*/
type T5 = 'a=1&b=2&c=3'
type T6<S> = S extends `${infer A}&${infer B}` ? A | T6<B> : S
type T7 = T6<T5>

/*
1.  -   `f1` 是一个函数,接受一个 `number` 和一个 `string`,返回一个包含该 `number` 和 `string` 长度的数组。

2.  T8 和 T9:
    -   `T8<T>` 是一个条件类型,它检查 `T` 是否是一个函数,如果是,它将返回函数的第一个参数的类型,否则返回 `never`。
    -   `T9` 应用 `T8` 到 `f1`,因此 `T9` 将是 `number`。
*/
function f1(a: number, b: string): [number, number] {
    return [a, b.length]
}
type T8<T> = T extends (a: infer A, b: string) => any ? A : never
type T9 = T8<typeof f1>

/*
3.  T10 和 T11:
    -   `T10<T>` 是一个条件类型,它检查 `T` 是否是一个函数,如果是,它将返回函数的返回类型,否则返回 `never`。
    -   `T11` 应用 `T10` 到 `f1`,因此 `T11` 将是 `[number, number]`。
*/
type T10<T> = T extends (a: number, b: string) => infer R ? R : never;
type T11 = T10<typeof f1>

/*
4.  T12 和 T13:
    -   `T12<T>` 是一个条件类型,它检查 `T` 是否是一个函数,如果是,它将返回函数的第二个参数的类型,否则返回 `never`。
    -   `T13` 应用 `T12` 到 `f1`,因此 `T13` 将是 `string`。
*/
type T12<T> = T extends (a: any, b: infer B) => any ? B : never
type T13 = T12<typeof f1>

/*
5. T14 和 T15:
    -   `T14<T>` 是一个条件类型,它检查 `T` 是否是一个函数,如果是,它将返回一个新的函数类型,其参数和返回类型与原函数相反。
    -   `T15` 应用 `T14` 到 `f1`,因此 `T15` 将是 `(b: string, a?: number) => [number, number]`。
*/
type T14<T> = T extends (a: infer A, b: infer B) => infer C ? (a: B, b?: A) => C : never
type T15 = T14<typeof f1>

/*
6.  P1 和 T26:
    -   `P1` 定义了一个返回 `number[]` 的 `Promise` 类型。
    -   `T26<T>` 是一个条件类型,它检查 `T` 是否是一个 `Promise`,如果是,它将返回 `Promise` 的解析类型,否则返回 `T`。
    -   `T27` 应用 `T26` 到 `P1`,因此 `T27` 将是 `number[]`。
*/
type P1 = Promise<number[]>
type T26<T> = T extends Promise<infer R> ? R : never
type T27 = T26<P1>

/*
7.  P2 和 T28:
    -   `P2` 定义了一个嵌套的 `Promise` 类型,最内层是 `1`。
    -   `T28<T>` 是一个递归条件类型,它检查 `T` 是否是一个 `Promise`,如果是,它将递归地应用 `T28` 到 `Promise` 的解析类型,否则返回 `T`。
    -   `T29` 应用 `T28` 到 `P2`,因此 `T29` 将是 `1`。
*/
type P2 = Promise<Promise<Promise<1>>>
type T28<T> = T extends Promise<infer R> ? T28<R> : T
type T29 = T28<P2>