typescript 如何定义无限嵌套的对象数组类型?

2020-11-27 16:07:54 +08:00
 daguaochengtang
我有类似这样一个数组:

```javascript
const array = [
{
name: 'a',
children: [
{
name: 'aa',
children: [
{
name: 'aaa',
children: []
}
]
},
{
name: 'ab',
children: []
},
]
},
{
name: 'b',
children: [
{
name: 'ba',
children: []
},
{
name: 'bb',
children: []
},
]
},
]
```

我希望定义一个函数来展平这个多维嵌套的对象数组,把它变成这样:

```javascript
[
{name: 'a', children: []},
{name: 'aa', children: []},
{name: 'aaa', children: []},
{name: 'ab', children: []},
{name: 'b', children: []},
{name: 'ba', children: []},
{name: 'bb', children: []},
]
```

我的函数是这样写的:

```javascript
function flat(array, children = 'children') {
const res = []
const recursive = (target) => {
target.map(item => {
res.push(item)
if(item.hasOwnProperty(children) && item[children].length) {
recursive(item[children])
}
})
}
recursive(array)
return res
}
```

到目前为止,需求是可以实现的。但是当我想用 typescript 来实现的时候,我发现我不知道该如何定义 array 的类型了。万 v 友,求帮助啊
发现 V2EX 对 markdown 代码块语法支持的不太好,贴个[有道云笔记地址]( http://note.youdao.com/noteshare?id=b80252fbd7248f58dc14446823ff90a1&sub=2839057A8A83481C9AE6D1632E63F819)
3250 次点击
所在节点    程序员
9 条回复
ytxbnahn
2020-11-27 16:14:30 +08:00
interface DataType {
name:string;
children:DataType[]
}
daguaochengtang
2020-11-27 16:19:18 +08:00
@ytxbnahn 可能我表达的不够清楚,{name,children}只是举个例子,实际上 flat 函数应该处理的是一个泛型的对象数组,比如可能是[{a, b, c, children}]或者[{x, y, children}],甚至我希望 children 是可以配置的,比如叫 child (参考我的 flat 函数,children 参数给了默认值是可以传入其它参数的)。这样的话要怎么定义呢?
ytxbnahn
2020-11-27 16:25:14 +08:00
@nikolausliu

flat<DataType>(array,children)

function flat<T>(array:T, children = 'children') {

}
joesonw
2020-11-27 16:30:59 +08:00
interface Data<T> {
[k: string]: string | Array<Data<T>>;
}

function flat<T>(array: Data<T>, children: keyof T) {}

flat({ children: [{ a: '123' }] }, 'children')
daguaochengtang
2020-11-27 17:01:03 +08:00
@joesonw
感谢你提供的思路,我改写了下,现在成功了:
export interface Obj<T>{
[k: string]: any
children: Array<Obj<T>>
}

export function flatObjectArray<T>(array: Array<Obj<T>>): Array<Obj<T>> {
const res: Array<Obj<T>> = []
function recursive(target: Array<Obj<T>>) {
target.map((item: Obj<T>) => {
res.push(item)
if(item.hasOwnProperty('children') && item.children.length) {
recursive(item.children)
}
})
}
recursive(array)
return res
}



不过,我现在是把 children 这个参数固定死了,如果我希望使用动态的 children,并且在函数定义中明确指定 children 这个参数不能是其它 key 的话(你上面 children: keyof T 的写法 children 实际可以传入 a,b,c 等),应该怎么写呢?

我初步的想法是

export interface Obj<T>{
[k: string]: any
[children: string]: Array<Obj<T>>
}
可是应该怎么定义函数的 children 参数的类型呢?
Flands
2020-11-28 10:27:28 +08:00
碰到这种极其复杂的类型判断我都是一个`any[]`上去...
可能太懒了吧,用单测跑过就行
joesonw
2020-11-29 16:10:46 +08:00
@nikolausliu 大概是可以的, 有一段时间没写前端了. 但是可以试试 interface Obj<T, K extends string> { [key in K]: Array<Obj<T, K>> } 类似的

https://stackoverflow.com/questions/56419558/typescript-how-to-use-a-generic-parameter-as-object-key
daguaochengtang
2020-11-29 20:40:42 +08:00
@joesonw 好嘞,我试试
buhi
2020-11-30 10:22:52 +08:00
type MayhaveChildren<K extends string> = {
[k in K]: MayhaveChildren<K>[]
}

type Flatten<K extends string, T extends MayhaveChildren<K>> = T[]

function flatten<K extends string, T extends MayhaveChildren<K>>(data:T[], k: K & keyof T): Flatten<K, T>

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/729911

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX