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

TypeScript按点语法批量选取对象属性的类型定义求助

解决嵌套属性批量选取的TypeScript类型定义及函数标注问题

1. 完善PickManyByDotNotation泛型类型

你的核心需求是将多个点语法路径转换为对应的嵌套对象结构,需要通过路径转对象+对象合并的思路实现,而非递归处理数组元素。以下是完整的类型定义:

辅助类型:路径转嵌套对象

先实现将单个点路径转换为对应嵌套对象的类型:

type PathToObject<T, P extends string> =
  P extends `${infer K extends keyof T & string}.${infer R}`
    ? { [key in K]: PathToObject<T[K], R> }
    : P extends keyof T
    ? { [key in P]: T[P] }
    : never;

辅助类型:合并多个嵌套对象

实现递归合并多个对象类型,处理嵌套层级的合并:

type Merge<T extends object[]> = T extends [infer A extends object, ...infer B extends object[]]
  ? { [K in keyof A | keyof B]: K extends keyof A ? A[K] : K extends keyof B ? B[K] : never } extends infer M
    ? { [K in keyof M]: M[K] extends object ? Merge<[A[K] extends object ? A[K] : never, B[K] extends object ? B[K] : never]> : M[K] }
    : never
  : T extends [infer A extends object]
  ? A
  : {};

最终PickManyByDotNotation类型

结合上述两个辅助类型,遍历所有路径并合并结果:

// 保留你已实现的PickByDotNotation(可直接复用)
type PickByDotNotation<TObject, TPath extends string> =
    TPath extends `${infer TKey extends keyof TObject & string}.${infer TRest}`
    ? PickByDotNotation<TObject[TKey], TRest>
    : TPath extends keyof TObject
    ? TObject[TPath]
    : never;

// 完善后的PickManyByDotNotation
type PickManyByDotNotation<T, P extends string[]> = Merge<{ [K in keyof P]: PathToObject<T, P[K] & string> }>;

测试验证

用你的示例测试,结果完全符合预期:

interface Test {
   customer: {
      email: string;
      name: string;
      phone: string;
      id: string
   };
};
type PickMany = PickManyByDotNotation<Test, ['customer.email', 'customer.name']>;
// 类型结果:{ customer: { email: string; name: string } }

2. 为JavaScript函数添加TypeScript类型标注

假设你的函数名为pickManyByDot,以下是带完整类型标注的实现:

function pickManyByDot<T extends object, P extends string[]>(
  obj: T,
  paths: P
): PickManyByDotNotation<T, P> {
  const result = {} as PickManyByDotNotation<T, P>;
  
  paths.forEach(path => {
    const keys = path.split('.');
    let source = obj;
    let target = result as any;
    
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];
      // 初始化嵌套对象(非最后一层)
      if (i < keys.length - 1 && !target[key]) {
        target[key] = {};
      }
      // 赋值(最后一层)或进入下一层
      target[key] = i === keys.length - 1 ? source[key] : target[key];
      source = source[key as keyof typeof source];
      target = target[key];
    }
  });
  
  return result;
}

使用示例

const testData: Test = {
  customer: {
    email: 'user@example.com',
    name: 'John Doe',
    phone: '123456789',
    id: '1001'
  }
};

const pickedData = pickManyByDot(testData, ['customer.email', 'customer.name']);
// pickedData类型:{ customer: { email: string; name: string } }
// 运行时值:{ customer: { email: 'user@example.com', name: 'John Doe' } }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:12:26