条件类型 是 ts 中一个非常高级的内容。建议好好读更新日志来学习。

我主要讲一下我实际中用到的情况:

条件判断

  1. type TypeName<T> =
  2. T extends string ? "string" :
  3. T extends number ? "number" :
  4. T extends boolean ? "boolean" :
  5. T extends undefined ? "undefined" :
  6. T extends Function ? "function" :
  7. "object";
  8. type T0 = TypeName<string>; // "string"
  9. type T1 = TypeName<"a">; // "string"
  10. type T2 = TypeName<true>; // "boolean"
  11. type T3 = TypeName<() => void>; // "function"
  12. type T4 = TypeName<string[]>; // "object"

distributive conditional types

注意一下,如果我们输入的参数是 union type,则会被拆开

  1. type T10 = TypeName<string | (() => void)>; // "string" | "function"
  2. type T12 = TypeName<string | string[] | undefined>; // "string" | "object" | "undefined"
  3. type T11 = TypeName<string[] | number[]>; // "object"

因为对参数的 union 会被 ts 先拆开分别求值

  1. TypeName<string | (() => void)>
  2. TypeName<string> | TypeName<() => void)>
  3. "string" | "function"

如果我们想要保证不被拆开,则我们可以这样子写

  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. : 'other';
  12. type T0 = TypeName<string>; // "string"
  13. type T1 = TypeName<'a'>; // "string"
  14. type T2 = TypeName<true>; // "boolean"
  15. type T3 = TypeName<() => void>; // "function"
  16. type T4 = TypeName<string[]>; // "other"
  17. type T10 = TypeName<string | (() => void)>; // "other"
  18. type T12 = TypeName<string | string[] | undefined>; // "other"
  19. type T11 = TypeName<string[] | number[]>; // "other"

Type inference in conditional types

我们可以通过 infer 获取类型中的部分结构,组装成新的类型:

  1. type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
  2. type PromiseType<T extends Promise<any>> = T extends Promise<infer U>
  3. ? U
  4. : never;
  5. type T = PromiseType<Promise<{a:number}>> // {a:number}
  6. type Required<T> = { [P in keyof T]-?: T[P] };
  7. type T1 = Required<{a?:number}> // {a:number}