Рекурсивные определения типов
Безопасно записывайте типы, ссылающиеся на самих себя
«Рекурсивные определения типов» — бесплатный урок 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 — локальная установка не требуется.
Все уроки этого курса
- Рекурсивные определения типов
- Типизация древовидных структур
- Типы значений JSON
- Глубина и ограничения рекурсии