ProgrammazioneFrontend разработчик

Как работает механизм типизированных шаблонных строк (Template Literal Types) в TypeScript и для чего он нужен?

Supera i colloqui con l'assistente IA Hintsage

Ответ.

История вопроса

TypeScript долгое время позволял описывать литеральные типы для отдельных строковых или числовых значений, однако с появлением шаблонных литералов появилась потребность в типизации конкретных шаблонов строк. Template Literal Types добавляют возможность описывать типы, основанные на шаблонном соединении строк, что обеспечивает статическую валидацию структуры строковых значений.

Проблема

Проверить соответствие строки определенному формату (например, 'user_42') средствами обычных string-типов невозможно — они слишком общие. Без шаблонных типов компилятор не может гарантировать, что строка будет подходить под строго заданный паттерн.

Решение

Template Literal Types позволяют формировать сложные строковые типы на этапе компиляции и обеспечивать строгую проверку их соответствия определенным шаблонам.

Пример кода:

type UserId = `user_${number}`; function loadUser(id: UserId) { // ... } loadUser('user_123'); // корректно loadUser('admin_123'); // ошибка компиляции

Ключевые особенности:

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

Вопросы с подвохом.

Можно ли использовать Template Literal Types только с number/literal? Можно ли использовать свои строковые литералы в шаблоне?

Можно использовать любые литеральные типы — строки, числа, объединения:

type EventType = `event_${'click' | 'hover'}`; // event_click | event_hover

Можно ли передать обычную строку, если функция ожидает тип Template Literal?

Нет, если тип явно ожидает литерал-шаблон, просто string не подойдет:

function handler(type: `btn_${string}`) {} handler('btn_click'); // ок handler('button'); // ошибка компиляции

Работают ли шаблонные строковые типы с mapped types и keyof?

Да, Template Literal Types отлично комбинируются с mapped types и ключами объектов:

const colors = {red: 1, blue: 2}; type ColorKey = keyof typeof colors; type ColorClass = `color-${ColorKey}`; // color-red | color-blue

Типовые ошибки и анти-паттерны

  • Использование шаблонного типа там, где подходит любой string
  • Слишком агрессивные шаблонные типы, не оставляющие гибкости
  • Привязка типов к runtime-значениям, которые не контролируются компилятором

Пример из жизни

Негативный кейс

API принимает идентификаторы вида 'user_XXX', функция не типизирована — возможно подать любую строку, при ошибке на сервере возникают баги.

Плюсы:

  • Нет ограничений на значение

Минусы:

  • Команда ошибается, подавая неверные строки; тесты поверхностны

Позитивный кейс

Используется тип UserId = user_${number}, перед компиляцией гарантируется корректность аргументов функций и безопасные запросы к серверу.

Плюсы:

  • Снижение числа ошибок, строгая типовая валидация
  • Улучшение автодополнения и читаемости кода

Минусы:

  • Требует актуализации шаблонных типов при смене схемы данных