类型推导的妙用

TypeScript 的类型推导能力远比我们想象的强大。善用 infer 关键字可以做到很多有趣的事情。

提取函数返回类型

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function fetchUser() {
  return { name: 'XC', age: 25 };
}

type User = ReturnType<typeof fetchUser>;
// { name: string; age: number }

提取 Promise 内部类型

type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;

type Result = Awaited<Promise<Promise<string>>>;
// string

模板字面量类型

TypeScript 4.1 引入的模板字面量类型是一个强大的特性:

type EventName = `on${Capitalize<'click' | 'focus' | 'blur'>}`;
// 'onClick' | 'onFocus' | 'onBlur'

条件类型的实际应用

type IsArray<T> = T extends any[] ? true : false;

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

实用工具类型

DeepPartial

type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

NonNullableKeys

type NonNullableKeys<T> = {
  [K in keyof T]-?: undefined extends T[K] ? never : K;
}[keyof T];

总结

TypeScript 的类型系统是图灵完备的,理论上可以在类型层面做任何计算。当然,日常开发中我们不需要走那么极端,掌握这些实用技巧就足够了。

类型不是束缚,而是你的安全网。