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
相关产品推荐
相关产品推荐

