条件类型,分布式条件类型,infer 
1.条件类型 
条件类型的语法类似于我们平时常用的三元表达式:
ts
ValueA === ValueB ? Result1 : Result2;
TypeA extends TypeB ? Result1 : Result2;条件类型绝大部分场景下会和泛型一起使用,泛型参数的实际类型会在实际调用时才被填充(类型别名中显式传入,或者函数中隐式提取),而条件类型在这一基础上,可以基于填充后的泛型参数做进一步的类型操作:
ts
type LiteralType<T> = T extends string ? 'string' : 'other'
type Res1 = LiteralType<'给我一个div'> // "string"
type Res2 = LiteralType<999> // "other"同三元表达式可以嵌套一样,条件类型中也常见多层嵌套:
ts
export type LiteralType<T> = T extends string
  ? 'string'
  : T extends number
    ? 'number'
    : T extends boolean
      ? 'boolean'
      : T extends null
        ? 'null'
        : T extends undefined
          ? 'undefined'
          : never
type Res1 = LiteralType<'给我一个div'> // "string"
type Res2 = LiteralType<999> // "number"
type Res3 = LiteralType<true> // "boolean"2.分布式条件类型 
提示
分布式条件类型,也称条件类型的分布式特性,是条件类型在满足一定情况下会执行的逻辑
1. 分布式作用的条件 
例子:
ts
type Condition<T> = T extends 1 | 2 | 3 ? T : never
/**
 * Res1:  1 | 2 | 3
 * 理论上这里应该返回 1 | 2 | 3 | 4 | 5 但是由于代码执行时遵循了分布式条件特性,
 * 返回结果为 1 | 2 | 3
 */
type Res1 = Condition<1 | 2 | 3 | 4 | 5>
/**
 * 这里没有遵循条件时分布特性 返回 never
 */
type Res2 = 1 | 2 | 3 | 4 | 5 extends 1 | 2 | 3 ? 1 | 2 | 3 | 4 | 5 : never条件分布式起作用的条件
- 类型参数需要通过泛型参数的方式传入,而不能直接进行条件类型判断(如 Res2 中)
- 类型参数需要是一个联合类型
2.条件分布式的效果 
条件分布式特性会将联合类型拆开来,每个分支分别进行一次条件类型判断,再将最后的结果合并起来:
ts
type Demo<T> = T extends string ? '123' : '456'
type res = Demo<string | number>  // "123" | "456"
/**
 * 以上代码在执行时相当于将传入的 string | number类型拆开类执行了两次 Demo的逻辑
 *  再合并为联合类型返回:
 */
// 执行了一下逻辑:
(string extends string ? '123' : '456') | (number extends string ? '123' : '456')内置的工具类型Exclude,Extract等就是利用了分布式条件特性实现
ts
type a = 1 | 2 | 3
type b = 2 | 3 | 5
/**
 *  type Extract<T, U> = T extends U ? T : never;
 */
type x = Extract<a, b> // 2 | 33.阻止分布式条件作用 
在达到特定的条件下,分布式特性会起作用,但有时可能并不需要这样的特性,只是单纯的封装一个类型来判断两个联合类型的兼容性,此时可以在条件类型中的extends关键字两侧给类型添加[]来阻止分布式特性:
ts
type Demo<T, U> = T extends U ? 'true' : 'false'
// 遵循分布式特性返回 "false" | "true"
type c = Demo<1 | 2, 3 | 2 | 4>
/* extends关键字两侧的类型添加[]让其成为元组来阻止分布式特性 */
type Demo1<T, U> = [T] extends [U] ? 'true' : 'false'
// "false"
type d = Demo1<1 | 2, 3 | 2 | 4>3.infer关键字 
TypeScript中支持通过infer关键字来在条件类型中提取类型的某一部分信息,简化了多条件类型的情况
需求: 定义类型别名Res<T>,当泛型T为数组时提取数组项的类型,否则直接返回传入的类型
ts
type n = number[]
type s = string[]
type Res<T> = T extends number[] ? number : T extends string[] ? string : T
type c = Res<n> // number
type d = Res<s> // string
type f = Res<boolean> // boolean以上代码使用infer关键字简化:
ts
type n = number[]
type s = string[]
/* 使用infer推断出数组项的类型 */
type Res<T> = T extends Array<infer R> ? R : T
type c = Res<n> // number
type d = Res<s> // string
type f = Res<boolean> // boolean提示
infer是 inference 的缩写,意为推断,如 infer R 中 R 就表示 待推断的类型。 infer 只能在条件类型中使用
1. 推断函数参数类型 
- 所有参数组成的元组类型
ts
type Func = (...args: any[]) => any
/**
 * infer R推断的时剩余参数args的类型,是一个元组
 */
type FuncParams<T extends Func> = T extends (...args: infer R) => any ? R : never
//  [val: string, v: number]
type c = FuncParams<(val: string, v: number) => void>- 指定位置参数的类型
ts
type Func = (...args: any[]) => any
/**
 * 推断第二个参数的类型,被推断参数后面使用 ...any[] 表示剩余的类型集合
 */
type FuncParams<T extends Func> = T extends (...args: [any, infer R, ...any[]])
=>
any ? R : never
// number
type c = FuncParams<(val: string, v: number, c: boolean) => void>2. 推断函数返回值类型 
ts
type FuncParams<T extends Func> = T extends (...args: any[]) => infer R ? R : never
//  string | number
type c = FuncParams<(val: string) => string | number>3. 推断数组类型 
- 数组项类型
ts
type Item<T> = T extends Array<infer R> ? R : never
// string | number | boolean
type It = Item<[string, number, boolean]>- 数组项类型调换位置
ts
type SwapStartAndEnd<T extends any[]> = T extends [
  infer Start,
  ...infer Center,
  infer End
]
  ? [End, ...Center, Start]
  : T
// ["end", number, boolean, string]
type Res = SwapStartAndEnd<[string, number, boolean, 'end']>