簡體   English   中英

在打字稿中遞歸更新嵌套對象中的值

[英]Update values in nested object recursively in typescript

我們需要在打字稿中使用遞歸更新嵌套對象中的對象。需要向嵌套對象中的對象添加額外的屬性。 嵌套會隨着時間的推移而改變,因此遞歸只會起作用 下面是輸入數據:

[
  {
    "headerName": "Group 1",
    "children": [
      {
        "field": "G1-C1"
      },
      {
        "field": "G1-C2"
      }
    ]
  },
  {
    "headerName": "Group 2",
    "children": [
      {
        "headerName": "G2 - C1",
        "children": [
          {
            "field": "G2 - C1-C1"
          },
          {
            "field": "G2 - C1-C2"
          }
        ]
      },
      {
        "field": "G2-C2"
      },
      {
        "field": "G2-C3"
      }
    ]
  },
  {
    "headerName": "Group3",
    "children": [
      {
        "field": "G3-C1"
      },
      {
        "field": "G3-C2"
      }
    ]
  }
]

需要轉換為:

[
  {
    "headerName": "Group 1",
    "children": [
      {
        "field": "G1-C1",
        "visible": true,
        "width": 200,
        "headerName": "Group1"
      },
      {
        "field": "G1-C2",
        "visible": true,
        "width": 200,
        "headerName": "Group1"
      }
    ]
  },
  {
    "headerName": "Group 2",
    "children": [
      {
        "headerName": "G2 - C1",
        "children": [
          {
            "field": "G2 - C1-C1",
            "width": 200,
            "headerName": "Group2-C1"
          },
          {
            "field": "G2 - C1-C2",
            "width": 200,
            "headerName": "Group2-C1"
          }
        ]
      },
      {
        "field": "G2-C2",
        "width": 200,
        "headerName": "Group2"
      },
      {
        "field": "G2-C3",
        "width": 200,
        "headerName": "Group2"
      }
    ]
  },
  {
    "headerName": "Group3",
    "children": [
      {
        "field": "G3-C1",
        "width": 200,
        "headerName": "Group3"
      },
      {
        "field": "G3-C2",
        "width": 200,
        "headerName": "Group3"
      }
    ]
  }
]

嘗試了幾種方法,但無法找到方法。 如果有任何快速方法可以找到此問題的解決方案,那將是非常有幫助的。 下面的方法有效,但不確定它是否正確。

          formatData(columns: any) {     
            columns.forEach((i: any,index) => {
              if (i.hasOwnProperty('children')) {       
                this.formatData(i.children);
              } else {       
                columns[index] = {...{ field : i.field, headerName: 
                i.field, sortable: true, hide: false }};                    
              }      
            });            
          } 
           

首先,我們需要定義數據結構的類型:


type WithChildren = {
  headerName: string,
  children: DataStructure[]
}

type WithoutChildrenInput = {
  field: string,
}


type WithoutChildrenOutput = {
  field: string,
} & Pick<WithChildren, 'headerName'>

type DataStructure = WithChildren | WithoutChildrenInput

type DataStructureOutput = WithChildren | WithoutChildrenOutput

然后我們可以定義我們的邏輯:

const fieldOutput = (
  field: string,
  headerName: string
) => ({
  field,
  headerName,
  visible: true,
  width: 200,
})

const childrenOutput = (headerName: string, children: DataStructure[]) => (
  { headerName, children: builder(children, headerName) }
)

const withChildren = <Obj, Prop extends string>(obj: DataStructure)
  : obj is WithChildren =>
  Object.prototype.hasOwnProperty.call(obj, 'children');

const builder = (data: DataStructure[], headerName = ''): DataStructureOutput[] =>
  data.reduce<DataStructureOutput[]>((acc, elem) =>
    withChildren(elem)
      ? [...acc, childrenOutput(elem.headerName, elem.children)]
      : [...acc, fieldOutput(elem.field, headerName)], [])

const result = builder(data)

我創建了兩個助手: childrenOutputfieldOutput

fieldOutput - 只是創建一個字段實體的普通對象。 沒什么特別的

childrenOutput - 生成帶有子項的預期數據結構,並在 hood builder函數下調用。

withChildren - 是用戶定義的 typeguard ,有助於縮小類型

您可能認為在定義函數之前調用函數是一種不好的做法。 您可以使用function關鍵字聲明builder或將第三個參數傳遞給childrenOutput如下所示:

const childrenOutput = (headerName: string, children: DataStructure[], callback: (data: DataStructure[], headerName: string) => DataStructureOutput[]) => (
  { headerName, children: builder(children, headerName) }
)

它是由你決定。

全碼:



type WithChildren = {
  headerName: string,
  children: DataStructure[]
}

type WithoutChildrenInput = {
  field: string,
}


type WithoutChildrenOutput = {
  field: string,
} & Pick<WithChildren, 'headerName'>

type DataStructure = WithChildren | WithoutChildrenInput

type DataStructureOutput = WithChildren | WithoutChildrenOutput

const data: DataStructure[] = [
  {
    "headerName": "Group 1",
    "children": [
      {
        "field": "G1-C1"
      },
      {
        "field": "G1-C2"
      }
    ]
  },
  {
    "headerName": "Group 2",
    "children": [
      {
        "headerName": "G2 - C1",
        "children": [
          {
            "field": "G2 - C1-C1"
          },
          {
            "field": "G2 - C1-C2"
          }
        ]
      },
      {
        "field": "G2-C2"
      },
      {
        "field": "G2-C3"
      }
    ]
  },
  {
    "headerName": "Group3",
    "children": [
      {
        "field": "G3-C1"
      },
      {
        "field": "G3-C2"
      }
    ]
  }
]

const fieldOutput = (
  field: string,
  headerName: string
) => ({
  field,
  headerName,
  visible: true,
  width: 200,
})

const childrenOutput = (headerName: string, children: DataStructure[], callback: (data: DataStructure[], headerName: string) => DataStructureOutput[]) => (
  { headerName, children: builder(children, headerName) }
)

const withChildren = <Obj, Prop extends string>(obj: DataStructure)
  : obj is WithChildren =>
  Object.prototype.hasOwnProperty.call(obj, 'children');

const builder = (data: DataStructure[], headerName = ''): DataStructureOutput[] =>
  data.reduce<DataStructureOutput[]>((acc, elem) =>
    withChildren(elem)
      ? [...acc, childrenOutput(elem.headerName, elem.children, builder)]
      : [...acc, fieldOutput(elem.field, headerName)], [])

const result = builder(data)

console.log({ result })

操場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM