我正在try 编写一个泛型函数,该函数接受一组值并构建一个树 struct .该函数的输出应返回与泛型类型相同的属性,但带有额外的递归children属性.

举个例子:

const items = [
  { id: 1, path: 'a', name: 'path1' },
  { id: 2, path: 'a,b', name: 'path2' },
  { id: 3, path: 'a,b,c', name: 'path3' },
];
interface Example {
  id: number;
  path: string;
}
export function test<T extends Example>(items: T[]) {
  // for brevity ... build the tree
  // I copy each item into a new object and add the children: { ...item, children: [] as ??? } as ???
  return tree;
}

在上面的示例中,树项目之一将是:

[{
  id: 1,
  path: 'a',
  name: 'path1',
  children: [{ id: 2, path: 'a,b', name: 'path2', children: [ {...} ] }]
}]

但是,我不确定如何指定返回类型.我希望所有相同的属性都可用,再加上子级数组,不管子级深入到什么程度.我try 了这样的方法:(T & {children: T})[],但这只适用于一个级别的子元素.

感谢您的帮助,谢谢!

推荐答案

您正在寻找的类型可能是:

type MyTree<T> = T & { children: MyTree<T>[] }

其中我们必须给类型命名为MyTree<T>,这样我们就可以递归引用它.它是T intersected,具有一个包含children属性的对象,该属性本身是一个由MyTree个元素组成的array.现在您已经有了类型的名称,可以使用它了:

declare function test<T extends Example>(items: T[]): MyTree<T>[];

让我们用你的items分来测试一下:

const tree = test(items);
// ^? const tree: MyTree<{ id: number; path: string; name: string; }>[]

这看起来像是正确的类型,现在Tyescrip很高兴能像这样处理它

for (const t of tree) {
    console.log(t.name);
    for (const c of t.children) {
        console.log(c.name); // etc
    }
}

或者递归地像

function getNames(x: MyTree<{ name: string }>[]): string[] {
    return x.flatMap(t => [t.name, ...getNames(t.children)]);
}    
getNames(tree); // okay

Playground link to code

Typescript相关问答推荐

如何修复VueJS中的val类型不能赋给函数

类型脚本:类型是通用的,只能索引以供阅读.(2862)"

React Hook中基于动态收件箱定义和断言回报类型

动态判断TypScript对象是否具有不带自定义类型保护的键

为什么typescript要把这个空合并转换成三元?

对扩展某种类型的属性子集进行操作的函数

TypeScrip 5.3和5.4-对`Readonly<;[...number[],字符串]>;`的测试版处理:有什么变化?

带下拉菜单的Angular 响应式选项卡

使用KeyOf和Never的循环引用

如何将定义模型(在Vue 3.4中)用于输入以外的其他用途

从对象类型描述生成类型

尽管对象的类型已声明,但未解析的变量<;变量

如何以Angular 导入其他组件S配置文件

将对象的属性转换为正确类型和位置的函数参数

设置不允许相同类型的多个参数的线性规则

为什么类型脚本使用接口来声明函数?他的目的是什么.

基于泛型的类型脚本修改类型

在tabel管理区域react js上设置特定顺序

Svelte+EsBuild+Deno-未捕获类型错误:无法读取未定义的属性(读取';$$';)

断言同级为true或抛出错误的Typescript函数