条件类型的语法实际上就是三元表达式,举例 T extends U ? X : Y

条件类型 Conditional Types

通常我们看到的条件类型是和泛型一起使用的,使用条件类型可以根据使用者的传入参数类型来判别确定的类型。

  1. function pickSingleValue<T extends object, U extends keyof T>(
  2. obj: T,
  3. key: U
  4. ): T[U] {
  5. return obj[key]
  6. }

T extends objectU extends keyof T都是泛型约束,分别将T约束为对象类型和将U约束为T键名的字面量联合类型,我们通常使用泛型约束来做收窄类型约束。

以一个条件类型作为函数返回值的例子

  1. declare function strOrNum<T extends boolean>(x: T): T extends true ? string : number
  2. const strReturnType = strOrNum(true); //string
  3. const numReturnType = strOrNum(false); //number

在上面那种情况下,条件类型的判断会被延迟,因为此时的类型系统没有足够的信息来完成判断,只有待使用者调用该函数(入参x的类型),才可以完成推导。

如同三元表达式可以嵌套,条件类型也可以嵌套,这样可以将类型收拢到非常精确的范围内

  1. type TypeName<T> = T extends string
  2. ? string
  3. : T extends number
  4. ? number
  5. : T extends boolean
  6. ? boolean
  7. : T extends undefined
  8. ? undefined
  9. : T extends Function
  10. ? Function
  11. : object

分发条件类型 Distributive Conditional Types

在泛型中使用条件类型的时候,如果传入的是一个联合类型,就会变成分发的(distributive)

  1. type ToArray<T> = T extends any ? T[] : never
  2. type StrArrOrNumber = ToArray<string | number>

我们在使用的时候传入一个联合类型,这个条件类型就会被应用到联合类型的每个成员

条件类型 - 图1

这个过程,当我们在StrArrOrNumber传入string | number接下来遍历联合类型里的成员,相当于

ToArray<string> | ToArray<number>,所以结果为string[] | number[]