I'm struggling to define the type for a function that can visit a tree:
Give a structure like
[
{ name: "leaf" },
{ children: [
{ name: "sub-leaf" }
]}
]
A function that can visit it recursively can be defined like:
type VisitorResult = void | "break";
function visit<
const ChildrenKey extends string,
Items extends readonly (
| Record<ChildrenKey, Items>
| Record<ChildrenKey, never>
)[],
>(
items: Items,
childrenKey: ChildrenKey,
visitor: (
item: Items[0],
parents: readonly Record<ChildrenKey, Items>[],
) => VisitorResult,
): void {
function visitItems(
items: Items,
parents: readonly Record<ChildrenKey, Items>[],
): VisitorResult {
for (const item of items) {
if (visitor(item, parents) === "break") {
return "break";
}
if (
childrenKey in item &&
visitItems(item[childrenKey], [...parents, item]) === "break"
) {
return "break";
}
}
return;
}
visitItems(items, []);
}
The interesting part is that I want the key that contains the subtree be customizable by the caller.
Currently this function type doesn't really work, because:
- each leaf node doesn't need to be a record, i would like to allow a leaf node to be of any type, string, number, etc
- I can't make the following code satisfy the type constraint
interface Leaf {
name: string;
}
interface Group {
children: readonly Node[];
}
type Node = Leaf | Group;
const nodes: readonly Node[] = [{ name: "leaf" }, { children: [{ name: "sub-leaf" }] }];
visit(
nodes,
"children",
(node, ) => console.log(node),
);
Any help is really appreciated.