首页 > 解决方案 > 如何为 Typescript 中嵌套对象的每个子对象添加属性?

问题描述

我正在尝试键入一个函数,该函数addId输入一个对象并返回相同的对象,但_id: string向每个子对象添加一个属性。

例如,输入是从以下类构造的对象。

class A {
  a: number
  b: { bb: number }
  c: number[]

  constructor() {
    this.a = 1
    this.b = { bb: 2 }
    this.c = [1,2,3]
  }
}
const a = new A()

在这种情况下addId(a)会返回

A {
  _id: 'id1'
  a: 1
  b: { bb: 2, _id: 'id2' }
  c: [1,2,3]
}

参数 toaddId可以是任何类的对象,而不是具体的 class A。该参数可以从 json、对象和数组递归构建,并且可以具有任意嵌套深度。

我不是在寻找 的实现addId,只是在寻找返回类型。DeepReadonly<T>我认为解决方案将使用与此处定义的类型类似的技术: https ://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts

标签: typescriptrecursion

解决方案


怎么样:

type Smart<T> =
  T extends Function ? T :
  T extends object ? (
    { [K in keyof T]: Smart<T[K]> } &
    (T extends readonly any[] ? unknown : { _id: string })
  ) : T

如果T是一个非函数对象,那么你肯定想递归到它并Smart<T>为每个属性做。这适用于数组和常规对象。但是您只想将该_id属性添加到非数组对象,这就是我进行该T extends readonly any[]检查的原因。您可以确认它提供了您期望的输出:

declare class A {
  a: number
  b: { bb: number }
  c: number[]
}
type SmartA = Smart<A>;
/*
type SmartA = {
    a: number;
    b: {
        bb: number;
    } & {
        _id: string;
    };
    c: number[];
} & {
    _id: string;
}
*/

Playground 代码链接


推荐阅读