全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-21 8 分钟 ✍️ juanwangdev

TypeScript 嵌套递归工具封装

嵌套递归工具类型用于处理深层对象结构,遍历所有层级进行类型转换,下面梳理核心实现。

深层 Partial

内置 Partial<T> 仅处理第一层,深层对象需递归处理:

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

interface Config {
  database: {
    host: string;
    options: {
      timeout: number;
    };
  };
}

type PartialConfig = DeepPartial<Config>;
// 等价于:
// {
//   database?: {
//     host?: string;
//     options?: {
//       timeout?: number;
//     };
//   };
// }

const cfg: PartialConfig = {
  database: {
    options: { timeout: 5000 }
  }
};

深层 Readonly

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

interface State {
  user: {
    name: string;
    prefs: { theme: string };
  };
}

const state: DeepReadonly<State> = {
  user: { name: "Alice", prefs: { theme: "dark" } }
};

// state.user.name = "Bob";       // ❌
// state.user.prefs.theme = "light";  // ❌

深层 Required

TypeScript
type DeepRequired<T> = T extends object
  ? { [K in keyof T]-?: DeepRequired<T[K]> }
  : T;

interface OptionalConfig {
  database?: {
    host?: string;
    options?: {
      timeout?: number;
    };
  };
}

type FullConfig = DeepRequired<OptionalConfig>;
// 所有层级都变为必填

深层 Pick

TypeScript
type DeepPick<T, K extends string> = K extends `${infer First}.${infer Rest}`
  ? First extends keyof T
    ? { [P in First]: DeepPick<T[First], Rest> }
    : never
  : K extends keyof T
    ? { [P in K]: T[P] }
    : never;

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

type UserProfile = DeepPick<User, "id" | "profile.name" | "profile.address.city">;
// {
//   id: string;
//   profile: {
//     name: string;
//     address: {
//       city: string;
//     };
//   };
// }

深层 Omit

TypeScript
type DeepOmit<T, K extends string> = K extends `${infer First}.${infer Rest}`
  ? First extends keyof T
    ? { [P in First]: DeepOmit<T[First], Rest> } & Omit<T, First>
    : T
  : Omit<T, K>;

type SafeUser = DeepOmit<User, "profile.address.zip">;
// zip 字段被排除,其余保留

递归边界处理

避免无限递归(如处理数组/函数):

TypeScript
type DeepPartialSafe<T> = T extends Function | Date | RegExp
  ? T
  : T extends Array<infer U>
    ? Array<DeepPartialSafe<U>>
    : T extends object
      ? { [K in keyof T]?: DeepPartialSafe<T[K]> }
      : T;

interface WithArray {
  tags: { name: string; count: number }[];
  createdAt: Date;
}

type PartialWithArray = DeepPartialSafe<WithArray>;
// Date 不展开,数组元素递归处理

要点总结

  • 深层工具类型通过递归条件类型 T extends object ? ... : T 遍历所有层级
  • 映射类型 [K in keyof T] 配合递归调用实现逐层转换
  • 模板字面量类型 .${infer Rest} 实现路径式深层操作(DeepPick/DeepOmit)
  • 边界处理排除函数/Date/RegExp 等内置对象,避免无限递归
  • 数组需特殊处理:T extends Array<infer U> ? Array<DeepXXX<U>> : ...

📝 发现内容有误?点击此处直接编辑

← 上一篇 TypeScript 模板字面量类型与类型提取
下一篇 → TypeScript 自定义复杂工具类型
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库