Типобезопасность интерполяции
Извлекайте из строк переменные интерполяции и требуйте их указания
«Типобезопасность интерполяции» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 4 уроков всего.
Типобезопасная интерполяция
Сообщения часто содержат заполнители, например "Hello, {name}". Типобезопасная интернационализация извлекает имена этих заполнителей из типа строки сообщения и требует передать соответствующие аргументы.
Цель
Имея литеральный тип сообщения, мы хотим вычислить объект необходимых ему переменных, чтобы вызов t("greet", { name: "Ada" }) был обязательным, а отсутствие name считалось ошибкой компиляции.
Извлечение одного заполнителя
Условный тип на основе шаблонной строки извлекает имя переменной из строки с одним заполнителем. В настоящем коде шаблон записывается обратными кавычками как: строка, открывающая фигурная скобка, выводимая переменная V, закрывающая фигурная скобка, строка. Ниже этот сопоставитель обозначен как BraceMatch.
// Real TS pattern (backtick template literal):
// matches any text, then {V}, then any text; infers V.
type Var<S extends string> =
S extends BraceMatch<infer V> ? V : never;
type A = Var<"Hello, {name}">; // "name"Извлечение нескольких заполнителей
Продолжите рекурсию, чтобы собрать все заполнители в объединение. Шаблон извлекает одну переменную и оставшийся фрагмент, затем рекурсивно обрабатывает этот фрагмент.
// Pattern: any text, {V}, then Rest tail -- infer V and Rest.
type Vars<S extends string> =
S extends BraceMatchRest<infer V, infer Rest>
? V | Vars<Rest>
: never;
type B = Vars<"Hi {first} {last}!">; // "first" | "last"От имён к объекту аргументов
Преобразуйте объединение имён в тип обязательного объекта с помощью отображаемого типа.
type ArgsOf<S extends string> = {
[K in Vars<S>]: string | number;
};
type G = ArgsOf<"Hello, {name}">;
// { name: string | number }Нет заполнителей — нет аргументов
Если сообщение не содержит заполнителей, Vars имеет значение never, поэтому объект аргументов оказывается пустым. В этом случае параметр аргументов можно сделать необязательным.
type C = Vars<"Goodbye">; // never
type D = ArgsOf<"Goodbye">; // {} (empty)Типизированная функция перевода
Сделайте параметр аргументов зависимым от выбранного ключа, найдя литерал сообщения и вычислив его аргументы.
declare const messages: {
greet: "Hello, {name}";
invite: "Join {count} others";
};
declare function t<K extends keyof typeof messages>(
key: K,
args: ArgsOf<(typeof messages)[K]>
): string;Проверка в действии
Теперь компилятор требует указать именно те переменные, которые объявлены каждым сообщением.
t("greet", { name: "Ada" }); // ok
t("greet", {}); // Error: name is missing
t("invite", { count: 3 }); // ok
t("invite", { name: "x" }); // Error: count missing, name unexpectedНеобязательные аргументы для обычных сообщений
Используйте условную перегрузку, чтобы сообщения без заполнителей вообще не требовали второго аргумента.
type MaybeArgs<S extends string> =
Vars<S> extends never ? [] : [args: ArgsOf<S>];
declare function t2<K extends keyof typeof messages>(
key: K,
...rest: MaybeArgs<(typeof messages)[K]>
): string;Пользовательские разделители
Если в каталоге используются {{name}} или %{name}, соответствующим образом измените шаблонный строковый шаблон в Vars. Метод остаётся тем же, меняется только окружающий литерал.
Почему это важно
Отсутствующие или указанные с ошибкой переменные интерполяции — классический источник неисправных строк интерфейса ("Hello, undefined"). Извлечение этих переменных на уровне типов превращает такие случаи в ошибки компиляции и документирует контракт каждого сообщения.
Быстрая проверка
Проверьте своё понимание типобезопасности интерполяции.
Итоги
Сопоставляя с образцом литеральные типы сообщений с помощью шаблонных литералов и infer, Вы извлекаете имена заполнителей в объединение типов, сопоставляете их с объектом обязательных аргументов и заставляете функцию перевода требовать именно эти переменные; если их нет, аргументы становятся необязательными.
Часто задаваемые вопросы
Урок «Типобезопасность интерполяции» бесплатный?
Да — полный текст урока «Типобезопасность интерполяции» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 4 уроков всего.
Чему я научусь в уроке «Типобезопасность интерполяции»?
Извлекайте из строк переменные интерполяции и требуйте их указания Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать TypeScript Academy?
Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Типобезопасность интерполяции»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке TypeScript Academy?
Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Типизация ключей переводов
- Типобезопасность интерполяции
- Множественное число с типами
- Вывод типов с учётом локали