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

TypeScript中如何基于子集类型从对象提取属性生成新对象?

从TypeA对象提取TypeB结构的实现方法

方法一:手动提取(适合简单结构)

如果TypeB的结构比较固定且简单,直接手动提取对应属性即可,代码直观无额外依赖:

type TypeA = {a : number, b: number, c : {d: number, e: number}}
const ObjA = {a: 1, b: 2, c : {d : 3, e: 4}}
type TypeB = {a: number, c: {e: number}}

const ObjB: TypeB = {
  a: ObjA.a,
  c: { e: ObjA.c.e }
};

方法二:模板式通用提取函数(适合嵌套结构)

针对复杂嵌套结构或需要复用提取逻辑的场景,可以写一个递归pick函数,通过模板对象指定要保留的属性结构:

type TypeA = {a : number, b: number, c : {d: number, e: number}}
const ObjA = {a: 1, b: 2, c : {d : 3, e: 4}}
type TypeB = {a: number, c: {e: number}}

// 递归提取匹配模板结构的属性
function pick<T, U extends Partial<T>>(obj: T, template: U): U {
  const result = {} as U;
  for (const key in template) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      const objVal = obj[key];
      const templateVal = template[key];
      // 处理嵌套对象
      if (typeof objVal === 'object' && objVal !== null && typeof templateVal === 'object' && templateVal !== null) {
        result[key] = pick(objVal, templateVal) as U[typeof key];
      } else {
        result[key] = objVal as U[typeof key];
      }
    }
  }
  return result;
}

// 传入TypeB结构的模板(属性值用undefined占位)
const ObjB = pick(ObjA, { a: undefined, c: { e: undefined } }) as TypeB;

该方法类型安全性高,模板结构与TypeB完全对应,无需手动拼接路径字符串。

方法三:路径式通用提取函数(适合动态指定属性)

如果需要动态指定提取的属性路径(比如从配置读取路径),可以写一个支持路径字符串的递归提取函数:

type TypeA = {a : number, b: number, c : {d: number, e: number}}
const ObjA = {a: 1, b: 2, c : {d : 3, e: 4}}
type TypeB = {a: number, c: {e: number}}

// 生成对象的嵌套键路径类型(如"a"、"c.e")
type NestedKeys<T> = T extends object
  ? { [K in keyof T]: K | `${K}.${NestedKeys<T[K]>}` }[keyof T]
  : never;

// 辅助类型:根据路径生成目标类型
type PickNested<T, K extends string> = K extends `${infer Key}.${infer Rest}`
  ? Key extends keyof T
    ? { [P in Key]: PickNested<T[Key], Rest> }
    : never
  : K extends keyof T
  ? { [P in K]: T[K] }
  : never;

// 递归根据路径提取属性
function pickNested<T, K extends NestedKeys<T>>(obj: T, keys: K[]): PickNested<T, K> {
  const result = {} as any;
  keys.forEach(key => {
    const pathSegments = key.split('.');
    let currentObj = obj;
    let currentResult = result;

    for (let i = 0; i < pathSegments.length; i++) {
      const segment = pathSegments[i];
      if (i === pathSegments.length - 1) {
        currentResult[segment] = currentObj[segment as keyof typeof currentObj];
      } else {
        currentResult[segment] = currentResult[segment] || {};
        currentResult = currentResult[segment];
        currentObj = currentObj[segment as keyof typeof currentObj];
      }
    }
  });
  return result;
}

// 传入需要提取的路径数组
const ObjB = pickNested(ObjA, ['a', 'c.e']) as TypeB;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 01:15:19