0Pricing
TypeScript Academy · Урок

Рекурсивные определения типов

Безопасно записывайте типы, ссылающиеся на самих себя

«Рекурсивные определения типов» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 4 уроков всего.

Что такое рекурсивный тип

Рекурсивный тип — это тип, который ссылается на себя в собственном определении. Это позволяет описывать структуры данных неограниченной глубины.

type LinkedList<T> = {
  value: T;
  next: LinkedList<T> | null;
};
// next is the same type again, ending at null.

Тип связного списка

Классический пример: каждый узел содержит value и указатель next на другой узел либо null, обозначающий конец цепочки chain.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
const list: LinkedList<number> = {
  value: 1,
  next: { value: 2, next: null }
};
console.log(list.value, list.next?.value);

Базовый случай важен

Каждому рекурсивному типу нужен терминатор — здесь это null, чтобы рекурсия могла завершиться. Без него тип имел бы бесконечную глубину.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
const single: LinkedList<string> = { value: "only", next: null };
console.log(single.next);

Построение длинных цепочек

Можно создавать вложенность любой глубины: тип допускает любую длину, поскольку next сам является списком или значением null.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
const chain: LinkedList<number> = {
  value: 10,
  next: { value: 20, next: { value: 30, next: null } }
};
console.log(chain.next?.next?.value);

Обход связного списка

Функция может пройти по цепочке, переходя по next, пока не достигнет null. Рекурсивный тип делает этот процесс полностью типобезопасным.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
function toArray<T>(list: LinkedList<T> | null): T[] {
  const out: T[] = [];
  let cur = list;
  while (cur) { out.push(cur.value); cur = cur.next; }
  return out;
}
const l: LinkedList<number> = { value: 1, next: { value: 2, next: null } };
console.log(toArray(l));

Рекурсивные функции для рекурсивных типов

Рекурсивные типы естественно сочетаются с рекурсивными функциями. Здесь длина вычисляется рекурсивным вызовом для next.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
function length<T>(list: LinkedList<T> | null): number {
  return list === null ? 0 : 1 + length(list.next);
}
const l: LinkedList<string> = { value: "a", next: { value: "b", next: null } };
console.log(length(l));

Добавление элемента в начало списка

Поскольку тип однороден, создавать новые списки легко: достаточно обернуть существующий список в качестве next нового головного узла.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
function prepend<T>(value: T, list: LinkedList<T> | null): LinkedList<T> {
  return { value, next: list };
}
const l = prepend(1, prepend(2, null));
console.log(l.value, l.next?.value);

Необязательные и допускающие null терминаторы

Завершить рекурсию можно с помощью null или сделать next необязательным. Оба варианта завершают рекурсию; выбирайте на основе желаемого представления конца списка.

type ListA<T> = { value: T; next: ListA<T> | null };
type ListB<T> = { value: T; next?: ListB<T> };
const a: ListA<number> = { value: 1, next: null };
const b: ListB<number> = { value: 1 };
console.log(a.value, b.value);

Рекурсивные типы вычисляются лениво

TypeScript раскрывает рекурсивный тип только настолько, насколько это действительно требуется при использовании. Определение может ссылаться на себя, не вызывая бесконечной работы.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
// Using two levels only expands two levels.
const l: LinkedList<number> = { value: 1, next: { value: 2, next: null } };
console.log(l.next?.value);

Отображение списка

Рекурсивное отображение преобразует каждое значение, сохраняя структуру, и возвращает новый список той же формы.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
function mapList<T, U>(list: LinkedList<T> | null, fn: (v: T) => U): LinkedList<U> | null {
  if (list === null) return null;
  return { value: fn(list.value), next: mapList(list.next, fn) };
}
const l: LinkedList<number> = { value: 1, next: { value: 2, next: null } };
console.log(mapList(l, x => x * 10)?.value);

Почему рекурсивные типы так полезны

Самоссылочные типы позволяют моделировать произвольно вложенные данные, списки, деревья и данные JSON с полной типобезопасностью и без фиксированного ограничения глубины в проекте.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
const l: LinkedList<boolean> = { value: true, next: { value: false, next: null } };
console.log(l.value, l.next?.value);

Быстрая проверка: рекурсивные типы

Проверьте, понимаете ли Вы определения рекурсивных типов.

Итоги: определения рекурсивных типов

Вы узнали, что рекурсивный тип ссылается на себя, нуждается в базовом случае, таком как null, для завершения и естественно сочетается с рекурсивными функциями для обхода, отображения и построения связных списков.

type LinkedList<T> = { value: T; next: LinkedList<T> | null };
const l: LinkedList<number> = { value: 1, next: null };
console.log(l.value);

Часто задаваемые вопросы

Урок «Рекурсивные определения типов» бесплатный?

Да — полный текст урока «Рекурсивные определения типов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 4 уроков всего.

Чему я научусь в уроке «Рекурсивные определения типов»?

Безопасно записывайте типы, ссылающиеся на самих себя Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать TypeScript Academy?

Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Рекурсивные определения типов»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке TypeScript Academy?

Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Рекурсивные определения типов
  2. Типизация древовидных структур
  3. Типы значений JSON
  4. Глубина и ограничения рекурсии
← Назад к TypeScript Academy