javascript - 在打字稿中递归更新嵌套对象中的值
问题描述
我们需要使用打字稿中的递归更新嵌套对象中的对象。需要为嵌套对象中的对象添加额外的属性。嵌套可能会随着时间的推移而改变,因此递归只会起作用以下是输入数据:
[
{
"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)
我创建了两个助手:childrenOutput
和fieldOutput
.
fieldOutput
- 只创建一个字段实体的普通对象。没什么特别的
childrenOutput
- 生成带有子项的预期数据结构并在 hoodbuilder
函数下调用。
withChildren
- 是一个用户定义的类型保护,有助于缩小类型
您可能认为在定义函数之前调用函数是一种不好的做法。您可以在此处builder
使用function
关键字声明或将第三个参数传递给childrenOutput
like:
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 })
推荐阅读
- javascript - 在 JavaScript 中创建随机 SVG 曲线,同时避免急转弯
- android-studio - 如何在现有的 keystore.jks (Android / Mac) 中更改 SHA-1 签名密钥
- es6-promise - 如何访问 Promise 中的函数
- css - CSS 强制动画在点击、活动或焦点时完全完成?
- java - WSL2 上的 Maven 看不到 JAVA_HOME
- laravel - Laravel Eloquent 关系二模型
- node.js - 为什么 fastify 路由中没有其他成功状态码?
- python - ArgumentError:uint8 的属性“T”的值不在允许值列表中:half、bfloat16、float、double、int32
- python - 语句必须用换行符或分号分隔
- python-3.x - 发生错误时如何使程序进一步工作?