V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
daguaochengtang
V2EX  ›  程序员

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

  •  
  •   daguaochengtang · 2020-11-27 16:07:54 +08:00 · 3440 次点击
    这是一个创建于 1439 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我有类似这样一个数组:

    ```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)
    9 条回复    2020-11-30 10:22:52 +08:00
    ytxbnahn
        1
    ytxbnahn  
       2020-11-27 16:14:30 +08:00   ❤️ 1
    interface DataType {
    name:string;
    children:DataType[]
    }
    daguaochengtang
        2
    daguaochengtang  
    OP
       2020-11-27 16:19:18 +08:00
    @ytxbnahn 可能我表达的不够清楚,{name,children}只是举个例子,实际上 flat 函数应该处理的是一个泛型的对象数组,比如可能是[{a, b, c, children}]或者[{x, y, children}],甚至我希望 children 是可以配置的,比如叫 child (参考我的 flat 函数,children 参数给了默认值是可以传入其它参数的)。这样的话要怎么定义呢?
    ytxbnahn
        3
    ytxbnahn  
       2020-11-27 16:25:14 +08:00
    @nikolausliu

    flat<DataType>(array,children)

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

    }
    joesonw
        4
    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
        5
    daguaochengtang  
    OP
       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
        6
    Flands  
       2020-11-28 10:27:28 +08:00
    碰到这种极其复杂的类型判断我都是一个`any[]`上去...
    可能太懒了吧,用单测跑过就行
    joesonw
        7
    joesonw  
       2020-11-29 16:10:46 +08:00   ❤️ 1
    @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
        8
    daguaochengtang  
    OP
       2020-11-29 20:40:42 +08:00
    @joesonw 好嘞,我试试
    buhi
        9
    buhi  
       2020-11-30 10:22:52 +08:00   ❤️ 1
    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>
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2967 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 14:38 · PVG 22:38 · LAX 06:38 · JFK 09:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.