Types That Reference Themselves
Recursive Types
Types can reference themselves — useful for tree shapes, JSON, and other nested structures.
What you'll learn
- Author a recursive type
- Model JSON
- Recognize the depth limit
A type can reference itself. Useful for nested data — comments with replies, file trees, the entirety of JSON.
A Tree
type Tree<T> = {
value: T;
children: Tree<T>[];
};
const t: Tree<string> = {
value: "root",
children: [
{ value: "a", children: [] },
{ value: "b", children: [
{ value: "b-1", children: [] },
]},
],
}; Tree<T> includes Tree<T>[] in its definition — a recursive
reference.
JSON
type Json =
| string
| number
| boolean
| null
| Json[]
| { [key: string]: Json };
const data: Json = {
name: "Ada",
age: 36,
tags: ["js", "ts"],
nested: { active: true },
}; A complete type for parsed JSON, defined in 6 lines.
A Comment Thread
type Comment = {
id: string;
text: string;
author: string;
replies: Comment[];
}; Each comment has its own list of replies — recursive.
Recursion Depth
TS has a depth limit on recursive type resolution — usually fine for any real data, but very deep recursion (50+ levels) can hit the limit:
// type instantiation is excessively deep and possibly infinite. If you hit this, your type is probably more complex than it needs to be.
Recursive Generic Types
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? DeepReadonly<T[K]>
: T[K];
}; Recursively make every nested property readonly. We cover the
mapped + conditional pieces in the next chapter.
End of Chapter
That wraps generics. Next chapter dives into TypeScript’s
advanced type tools — keyof, typeof, mapped types, conditional
types — the parts that make TS feel like a real programming
language.