Suppose we have the interface:
interface Node<C extends Node[] = any[]> {
children: C
}
Here, C is a generic that's a tuple that is the type of this node's children.
Let's define some nodes:
type Foo = Node<[]>
type Bar = Node<[Foo, Foo]>
type Baz = Node<[Bar]>
Baz is the root node. It is the parent of one Bar node, which is the parent of two Foo nodes. Foo has no children.
If I want to get the children of a node, I can do:
type TupleOfNodeChildren<N extends Node> = N['children'];
Here are some examples of this TupleOfNodeChildren type, which works as expected:
type T0 = TupleOfNodeChildren<Foo> // []
type T1 = TupleOfNodeChildren<Bar> // [Foo, Foo]
type T3 = TupleOfNodeChildren<Baz> // [Bar]
Now let's say that I want a type that is a union of every different type in the tuple. I can do:
type TypesOfNodeChildren<N extends Node> = TupleOfNodeChildren<N>[number];
And then of course our examples:
type T10 = TypesOfNodeChildren<Foo> // never
type T11 = TypesOfNodeChildren<Bar> // Foo
type T12 = TypesOfNodeChildren<Baz> // Bar
All of that works nice and fine. But what if I want something called TypesOfAllChildren, which is like TypesOfNodeChildren, but instead of just being a union of the immediate children, it is a union of all of the node's children?
This is how it would work:
type T20 = TypesOfAllChildren<Foo> // never
type T21 = TypesOfAllChildren<Bar> // Foo
type T22 = TypesOfAllChildren<Baz> // Bar | Foo <--- Includes types of deep children
Notice that T22 has both Bar, the immediate child of Baz, and then also Foo, which is the child of Bar.
I can't seem to get this TypesOfAllChildren type to work; it keeps complaining about a circular reference no matter what I try. I am assuming that you need some kind of recursion to get the types of all of the children, but I am not sure how to implement that without TypeScript complaining. Here is a playground with these types and examples.
EDIT:
Here is an example of what I tried:
type TypesOfAllChildren<N extends Node> = TypesOfNodeChildren<N> | TypesOfAllChildren<TypesOfNodeChildren<N>>;
// ~~~~~~~~~~~~~~~~~~ Recursively references itself
Adding an exit condition via a conditional type also doesn't work:
type TypesOfAllChildren<N extends Node> = TypesOfNodeChildren<N> | (TypesOfNodeChildren<N> extends never ? never : TypesOfAllChildren<TypesOfNodeChildren<N>>);