Home
avatar

.Sam

TypeScript 高级类型体操

类型体操是什么

TypeScript 的类型系统是图灵完备的,这意味着你可以在类型层面实现复杂的逻辑运算。社区把这种高级类型编程戏称为”类型体操”。

常用工具类型实现

DeepReadonly

递归地将对象所有属性变为只读:

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object
    ? T[K] extends Function
      ? T[K]
      : DeepReadonly<T[K]>
    : T[K];
};

interface Config {
  db: {
    host: string;
    port: number;
  };
  features: string[];
}

type ReadonlyConfig = DeepReadonly<Config>;
// 所有嵌套属性都变为 readonly

PathKeys

提取对象所有嵌套路径的联合类型:

type PathKeys<T, Prefix extends string = ""> = T extends object
  ? {
      [K in keyof T & string]: T[K] extends object
        ? `${Prefix}${K}` | PathKeys<T[K], `${Prefix}${K}.`>
        : `${Prefix}${K}`;
    }[keyof T & string]
  : never;

interface User {
  name: string;
  address: {
    city: string;
    zip: string;
  };
}

type UserPaths = PathKeys<User>;
// "name" | "address" | "address.city" | "address.zip"

条件类型与 infer

使用 infer 提取函数返回值中 Promise 的内部类型:

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

type A = UnwrapPromise<Promise<Promise<string>>>; // string
type B = UnwrapPromise<number>; // number

模板字面量类型

TypeScript 4.1 引入的模板字面量类型非常强大:

type EventName<T extends string> = `on${Capitalize<T>}`;

type Events = EventName<"click" | "focus" | "blur">;
// "onClick" | "onFocus" | "onBlur"

type CSSProperty = `${string}-${string}`;
const valid: CSSProperty = "background-color"; // ✅

实际应用场景

类型体操不只是炫技,在实际项目中有很多应用:

  1. API 类型安全 - 根据路由路径自动推导请求/响应类型
  2. 状态管理 - 确保 action 和 reducer 的类型匹配
  3. 表单验证 - 在类型层面约束表单字段和验证规则

掌握这些技巧能让你写出更安全、更具表达力的 TypeScript 代码。

TypeScript 前端