


Оператор satisfies проверяет, подходит ли выражение ожидаемому типу, сохраняя более конкретный тип самого выражения вместо замены его широкой аннотацией. Он появился в TypeScript 4.9. Это полезно для конфигураций и таблиц соответствий, где нужно одновременно проверить структуру и удобно обращаться к конкретным свойствам.
В примере Mentoring.digital конфигурация содержит числовое число повторов и текстовое название режима. Тип допускает оба вида значений, но это не должно мешать работе с заведомо текстовым полем.
type Option = "retries" | "mode";
type OptionValue = string | number;
const config = {
retries: 3,
mode: "safe"
} satisfies Record<Option, OptionValue>;
config.mode.toUpperCase();
config.retries.toFixed(0);
Объект проходит проверку Record. При этом компилятор знает, что mode является строкой, а retries числом. Если объявить переменную с широкой аннотацией Record<Option, OptionValue>, чтение свойства будет иметь тип string | number. Перед вызовом строкового метода понадобится сужение типа.
Это не означает, что satisfies всегда сохраняет буквальное значение вроде "safe" как единственный возможный тип. Вывод типов зависит от выражения и контекста. Здесь обычное изменяемое строковое свойство не нужно путать с неизменяемым строковым литералом.
const broken = {
retries: 3,
mdoe: "safe"
} satisfies Record<Option, OptionValue>;
// Ошибка: mdoe не входит в ожидаемый набор ключей.
Для такого литерала проверяются ожидаемые ключи и допустимые типы значений. Опечатка становится видна в месте объявления. Если вместо конечного объединения ключей использовать Record<string, OptionValue>, произвольные строковые имена будут разрешены. Тогда оператор не сможет определить, что mdoe было ошибкой в названии mode.
Правило зависит от выбранного контракта. Сам по себе satisfies не делает любой объект «строго проверенным» во всех возможных смыслах. Например, тип number не ограничивает число повторов диапазоном от нуля до пяти. Такое условие нужно задавать и проверять отдельно.
const fixedConfig = {
retries: 3,
mode: "safe"
} as const satisfies Record<Option, OptionValue>;
const mode: "safe" = fixedConfig.mode;
// fixedConfig.mode = "fast"; // Ошибка: readonly-свойство.
as const сохраняет литеральные типы и делает свойства этого литерала readonly на уровне TypeScript. satisfies при этом проверяет совместимость с контрактом. Эти части выполняют разные задачи. Такая запись не равна Object.freeze и не вводит запрет записи во время выполнения JavaScript.
Проверки типов TypeScript исчезают из выполняемого JavaScript. Если данные получены из JSON, нужно проверить их структуру во время выполнения. Особенно опасно полагаться на satisfies рядом со значением типа any: такой тип позволяет пропустить множество ошибок. На границе внешних данных используйте unknown и явную проверку или подходящий валидатор.
Для самопроверки запустите компилятор с --noEmit --strict. Убедитесь, что правильный объект проходит, опечатка ключа и неподходящий тип дают ошибку, а строковые методы правильного свойства доступны. Не считайте успешную компиляцию тестом реального ответа сервера.
Разобраться с выводом типов помогут курсы TypeScript. Границы статической и runtime-проверки удобно обсудить с наставником по TypeScript.