0Pricing
TypeScript Academy · Урок

Мини-анализатор маршрутов на уровне типов

Разбирайте пути маршрутов в типизированные объекты параметров

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

Цель

Мы создаём анализатор маршрутов, который читает путь вроде "users/:id/posts/:postId" и полностью во время компиляции создаёт типизированный объект параметров { id: string; postId: string }. Это реальный приём, используемый типизированными маршрутизаторами.

type Params = ParseRoute<"users/:id/posts/:postId">;
// Goal: { id: string; postId: string }

Распознавание параметра

Сегмент пути является параметром, если начинается с ":". Мы сопоставляем этот префикс с шаблонной строкой и выводим имя параметра после двоеточия.

Обозначения: в настоящем TypeScript шаблонные строковые типы записываются строками, ограниченными обратными кавычками и содержащими места для подстановок с долларом и фигурными скобками. В этих фрагментах мы показываем такой шаблон в виде Tpl<...>, перечисляя его части по порядку; например, шаблон в обратных кавычках, сопоставляющий сначала литеральный префикс, а затем Rest, выглядит как Tpl<'prefix', infer Rest>.

type ParamName<S> = S extends Tpl<':', infer Name> ? Name : never;
// Tpl<...> denotes a backtick template literal type: a colon then Name

type X = ParamName<':id'>;   // 'id'
type Y = ParamName<'users'>; // never

Разбиение пути

Сначала разделите маршрут на сегменты по "/", повторно используя тип Split. Затем каждый сегмент оказывается либо литералом, либо параметром.

type Split<S extends string, Sep extends string> =
  S extends Tpl<infer H, Sep, infer T> ? [H, ...Split<T, Sep>] : [S];
// Tpl<H, Sep, T> = a template literal type matching H, then Sep, then T

type Segs = Split<'users/:id', '/'>; // ['users', ':id']

Прямая рекурсия по шаблону

Можно также разобрать исходную строку без предварительного разбиения, сопоставляя по одному сегменту за раз. Сопоставьте всё до следующего "/", обработайте этот сегмент, а затем рекурсивно разберите остаток.

type ParseRoute<S extends string> =
  S extends Tpl<infer Seg, '/', infer Rest>
    ? SegParam<Seg> & ParseRoute<Rest>
    : SegParam<S>;
// Tpl<Seg, '/', Rest> matches a segment, a slash, then the rest

Параметр отдельного сегмента

Вспомогательный тип превращает один сегмент либо в объект с одним свойством (если это параметр), либо в пустой объект (если это литерал).

type SegParam<S extends string> =
  S extends Tpl<':', infer Name> ? { [K in Name]: string } : {};
// Tpl<':', Name> matches a colon followed by the param name

type X = SegParam<':id'>;   // { id: string }
type Y = SegParam<'posts'>; // {}

Объединение через пересечение

Каждый сегмент добавляет свои параметры через пересечение. Пустые объекты исчезают при пересечении, поэтому в итоговом типе остаются только настоящие параметры.

type Params = ParseRoute<"users/:id/posts/:postId">;
// { id: string } & {} & { postId: string } & {}
// = { id: string; postId: string }

Отслеживание разбора

Для "users/:id/posts/:postId":

  • Сегмент "users" -> {} , рекурсия для ":id/posts/:postId"
  • Сегмент ":id" -> { id: string }, рекурсия для "posts/:postId"
  • Сегмент "posts" -> {}, рекурсия для ":postId"
  • Сегмент ":postId" -> { postId: string }, базовый случай
type Final = { id: string } & { postId: string };

Очистка результата

Пересечение объектов отображается неудобно. Вспомогательный тип для «улучшения» разворачивает его в единый чистый тип объекта с помощью отображаемого типа по его ключам.

type Prettify<T> = { [K in keyof T]: T[K] } & {};

type Clean = Prettify<ParseRoute<"users/:id">>; // { id: string }

Использование анализатора

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

declare function route<P extends string>(
  path: P,
  handler: (params: Prettify<ParseRoute<P>>) => void
): void;

route("users/:id", p => { const id: string = p.id; });

Преимущество типизированных параметров

Теперь компилятор выводит params непосредственно из строки маршрута. Переименуйте параметр в пути — и каждый обработчик автоматически обновит ожидаемые ключи. Не нужен ручной интерфейс, и маршрут с обработчиком больше не расходятся.

route("users/:userId", p => {
  const u = p.userId; // ok
  // const x = p.id; // error: id does not exist
});

Расширение анализатора

Этот небольшой анализатор — основа полноценного типизированного маршрутизатора. Можно добавить типизированные значения (числовые параметры), подстановочные сегменты и необязательные сегменты, обогатив вспомогательный тип для отдельного сегмента дополнительными шаблонами. Структура с рекурсивным шаблоном останется прежней.

type SegParam2<S extends string> =
  S extends Tpl<':', infer N, '(number)'> ? { [K in N]: number }
  : S extends Tpl<':', infer N> ? { [K in N]: string }
  : {};
// Tpl<...> stands for a backtick template literal type pattern

Быстрая проверка

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

Итоги

Вы создали анализатор маршрутов, работающий во время компиляции.

  • Сопоставляйте каждый сегмент с помощью рекурсивного вывода по шаблонной строке.
  • Сегменты-параметры (:name) превращаются в { name: string }.
  • Литеральные сегменты превращаются в {} и исчезают при пересечении.
  • Prettify разворачивает результат в аккуратные параметры.

Далее — курс 25: сквозная безопасность типов с помощью tRPC.

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

Урок «Мини-анализатор маршрутов на уровне типов» бесплатный?

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

Чему я научусь в уроке «Мини-анализатор маршрутов на уровне типов»?

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

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

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

Сколько времени занимает урок «Мини-анализатор маршрутов на уровне типов»?

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

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

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

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

  1. Основы комбинаторов анализаторов
  2. Разделение строк на уровне типов
  3. Разбор с помощью шаблонных литералов
  4. Мини-анализатор маршрутов на уровне типов
← Назад к TypeScript Academy