Recursive Types

Types That Reference Themselves

Recursive Types

Types can reference themselves — useful for tree shapes, JSON, and other nested structures.

3 min read Level 3/5 #typescript#recursive#types
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.

`keyof` →