You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript中实现DeepPick类型?

实现TypeScript的DeepPick类型

要实现支持深度选取嵌套属性的DeepPick类型,核心是利用TypeScript的模板字面量类型、递归类型和条件类型来解析嵌套路径,并处理对象、数组等不同场景。以下是完整实现方案:

步骤1:拆分路径字符串为元组

首先定义一个辅助类型SplitPath,把类似'books.name'的嵌套路径拆分成字符串元组['books', 'name'],方便后续递归处理:

type SplitPath<T extends string> = T extends `${infer Head}.${infer Tail}` 
  ? [Head, ...SplitPath<Tail>] 
  : [T];

步骤2:实现单一路径的深度选取

接下来实现DeepPickSingle,处理单个路径的深层属性选取,同时兼容数组类型的场景:

type DeepPickSingle<T, Path extends string> = SplitPath<Path> extends [infer Key extends keyof T, ...infer Rest]
  // 如果是路径最后一段,直接选取该属性
  ? Rest extends []
    ? { [K in Key]: T[K] }
    // 如果当前属性是数组,对数组元素递归应用DeepPickSingle
    : T[Key] extends Array<infer U>
      ? { [K in Key]: Array<DeepPickSingle<U, Rest[number] extends string ? Rest[number] : never>> }
      // 如果当前属性是对象,递归处理剩余路径
      : T[Key] extends object
        ? { [K in Key]: DeepPickSingle<T[Key], Rest[number] extends string ? Rest[number] : never> }
        : never
  : never;

步骤3:合并多路径的选取结果

最后实现DeepPick,处理多个路径的联合类型,把每个路径的选取结果合并成一个完整类型:

// 辅助类型:合并交叉类型为普通对象类型
type Merge<T> = { [K in keyof T]: T[K] };

type DeepPick<T, Paths extends string> = Merge<
  {
    [P in Paths]: DeepPickSingle<T, P>;
  }[Paths]
>;

测试验证

用你提供的示例代码测试,完全符合预期:

interface TestBook {
    id: string;
    name: string;
}
interface TestUser {
    id: string;
    email: string;
    books: TestBook[];
}

const foo: DeepPick<TestUser, 'id' | 'books.name'> = {
  id: 'user-1',
  books: [{ name: 'TypeScript实战' }]
};
// foo的类型为:{ id: string; books: Array<{ name: string }> }

关键技术点说明

  • 模板字面量类型:通过${infer Head}.${infer Tail}语法拆分嵌套路径字符串,实现路径的逐层解析。
  • 递归类型:通过递归调用DeepPickSingle处理深层嵌套的属性,直到路径的最后一段。
  • 条件类型:区分当前属性是普通对象还是数组,分别处理数组元素的深层选取,保证类型兼容性。
  • 类型合并:用Merge辅助类型把多个路径生成的交叉类型转换为普通对象类型,避免类型显示异常。

扩展场景支持

这个实现还能处理可选属性、多层嵌套对象等场景:

interface TestAuthor {
  name: string;
  address?: { city: string; zip: number };
}
interface TestBookWithAuthor extends TestBook {
  author: TestAuthor;
}
interface TestUserWithAuthor extends TestUser {
  favoriteBook: TestBookWithAuthor;
}

const bar: DeepPick<TestUserWithAuthor, 'favoriteBook.author.address.city' | 'books.id'> = {
  favoriteBook: { author: { address: { city: '上海' } } },
  books: [{ id: 'book-1' }]
};
// bar的类型为:{ favoriteBook: { author: { address: { city: string | undefined } } }; books: Array<{ id: string }> }

内容的提问来源于stack exchange,提问作者teteyi3241

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 04:40:33