Recursive generic types let you define types that refer to themselves. This helps describe complex, nested data like trees or linked lists in a safe way.
Recursive generic types in Typescript
interface TreeNode<T> {
value: T;
children?: TreeNode<T>[];
}The interface TreeNode refers to itself inside the children property.
This allows nesting the same type inside itself to any depth.
undefined if it is the last.interface LinkedListNode<T> {
value: T;
next?: LinkedListNode<T>;
}interface NestedArray<T> {
value: T | NestedArray<T>[];
}interface EmptyNode<T> {
value: T;
next?: EmptyNode<T>;
}
// Edge case: single node with no next
const singleNode: EmptyNode<number> = { value: 5 };interface TreeNode<T> {
value: T;
children?: TreeNode<T>[];
}
// Edge case: empty children array
const leafNode: TreeNode<string> = { value: "leaf", children: [] };This program defines a recursive generic type TreeNode for a tree structure. It creates a tree of numbers with nested children. The printTree function prints each node's value with indentation to show the tree shape.
interface TreeNode<T> {
value: T;
children?: TreeNode<T>[];
}
// Create a tree of numbers
const rootNode: TreeNode<number> = {
value: 1,
children: [
{ value: 2 },
{
value: 3,
children: [
{ value: 4 },
{ value: 5 }
]
}
]
};
// Function to print tree values recursively
function printTree<T>(node: TreeNode<T>, indent = "") {
console.log(`${indent}${node.value}`);
if (node.children) {
for (const child of node.children) {
printTree(child, indent + " ");
}
}
}
console.log("Tree structure:");
printTree(rootNode);Time complexity of traversing recursive types depends on the number of nodes (usually O(n)).
Space complexity depends on recursion depth and stored data.
Common mistake: forgetting the optional property for recursion base case, causing infinite recursion or errors.
Use recursive generic types when you need to model nested or linked data safely with TypeScript's type system.
Recursive generic types let types refer to themselves to model nested data.
They are useful for trees, linked lists, and nested structures.
Always include a base case (like optional properties) to avoid infinite recursion.
Practice
recursive generic types in TypeScript?Solution
Step 1: Understand recursive generic types
Recursive generic types allow a type to refer to itself, which helps model nested or hierarchical data structures like trees or linked lists.Step 2: Compare options
Options A, C, and D do not describe recursive generics correctly. Only To define types that refer to themselves for nested or hierarchical data correctly states their purpose.Final Answer:
To define types that refer to themselves for nested or hierarchical data -> Option DQuick Check:
Recursive generics = self-referential types [OK]
- Thinking recursive generics are for runtime checks
- Confusing recursive generics with simple generics
- Assuming recursive generics flatten data
Solution
Step 1: Analyze recursive generic syntax
The type should refer to itself with the generic parameter and allow children to be an array of the same type or optional to avoid infinite recursion.Step 2: Check each option
type Node<T> = { value: T; children?: Node<T>[] }; correctly defines children as optional array ofNode<T>. type Node<T> = { value: T; children: Node[] }; misses generic parameter. type Node<T> = { value: T; children: Node<T> }; makes children a single Node, not array. type Node<T> = { value: T; children: T[] }; usesT[]which is incorrect.Final Answer:
type Node<T> = { value: T; children?: Node<T>[] }; -> Option BQuick Check:
Recursive generic with optional children array = type Node<T> = { value: T; children?: Node<T>[] }; [OK]
- Omitting generic parameter in recursive reference
- Making children non-array when it should be array
- Not making children optional causing infinite recursion
tree.children[0].children[0].value?
type TreeNode<T> = { value: T; children?: TreeNode<T>[] };
const tree: TreeNode<string> = {
value: "root",
children: [
{ value: "child1", children: [{ value: "grandchild1" }] },
{ value: "child2" }
]
};Solution
Step 1: Understand the type definition
TreeNode<T>has avalueof typeT. Here,Tisstring.Step 2: Trace the property access
tree.children[0].children[0].valueaccesses thevalueof a nested node, which is astringas per the generic type.Final Answer:
string -> Option AQuick Check:
Nested node value type = string [OK]
- Confusing node type with value type
- Assuming children or value can be undefined here
- Mixing up generic parameter with node type
type ListNode<T> = {
value: T;
next: ListNode<T>;
};Solution
Step 1: Analyze the recursive type definition
Thenextproperty refers toListNode<T>without being optional, so it requires an infinite chain.Step 2: Identify the fix
Makingnextoptional (next?: ListNode<T>) provides a base case to stop recursion.Final Answer:
Missing optional property for 'next' causing infinite recursion -> Option CQuick Check:
Recursive types need optional base case [OK]
- Forgetting to add '?' to recursive property
- Thinking TypeScript disallows recursive types
- Making unrelated properties optional
NestedArray<T> that represents an array of elements of type T or arrays of NestedArray<T> (nested arrays). Which of the following definitions correctly models this?Solution
Step 1: Understand the nested array structure
A nested array can be an array of elements of typeTor arrays of nested arrays recursively.Step 2: Evaluate each option
type NestedArray<T> = Array; correctly definesNestedArray<T>as an array whose elements are eitherTorNestedArray<T>. type NestedArray<T> = T | NestedArray<T>[]; is incorrect because it allows a single elementTwithout array wrapper. Options C and D misuse union and array placement.Final Answer:
type NestedArray<T> = Array<T | NestedArray<T>>; -> Option AQuick Check:
Nested arrays = arrays of T or nested arrays [OK]
- Allowing T alone without array wrapper
- Incorrect union placement outside array
- Confusing recursive generic with simple union
Ready to prove it?
Pass the test and this pattern moves unknown
