Что такое `as const` в TypeScript и зачем он нужен?
as const — это утверждение типа, которое говорит компилятору вывести самый узкий (литеральный) и неизменяемый (readonly) тип для значения вместо широкого. Используется, чтобы объекты, массивы и строки сохраняли точные литеральные значения и не мутировались.Что делает as const
По умолчанию TypeScript при выводе типов расширяет (widening) конкретные значения до более общих типов. Например, строка "admin" превращается в тип string, а число 5 — в number. Это удобно для переменных, которые могут изменяться, но иногда мешает, когда важно сохранить именно литеральное значение.
as const — это специальное утверждение типа (const assertion), которое отключает такое расширение и делает вывод типов максимально узким:
- строковые, числовые и булевы литералы остаются литералами, а не расширяются до
string/number/boolean; - массивы становятся кортежами (
tuple) фиксированной длины вместо обычного изменяемого массива; - все свойства объектов и элементы массивов помечаются как
readonly.
Пример без as const
Без утверждения переменная получает широкий тип, и её можно свободно менять на любое значение того же базового типа.
Пример с as const
С утверждением тип становится точным литералом, а попытка изменить значение вызывает ошибку компиляции.
Зачем он нужен
- Точные литеральные типы. Часто нужно, чтобы TypeScript знал не просто
string, а конкретно"GET" | "POST". Это критично для union-типов, статусов, экшенов Redux и т.д. - Неизменяемость (immutability).
readonlyзащищает от случайной мутации конфигов, констант и справочных данных прямо на уровне типов. - Кортежи вместо массивов. Массив с
as constпревращается в кортеж с фиксированными типами по позициям, что полезно для функций, принимающих аргументы по порядку. - Автоматический вывод union из объекта. В связке с
typeofиkeyofможно получить union значений объекта без дублирования типов вручную — не нужно писать тип отдельно, он выводится из самих данных. - Совместимость с строгими API. Многие библиотеки (например, для роутинга или конфигурации) ожидают литеральные типы, и
as const— самый простой способ их получить без явного описания интерфейсов.
Ограничения
as constделает только поверхностный (shallow)readonlyдля вложенных структур, но применяется рекурсивно ко всем уровням вложенности объекта или массива — то есть вложенные объекты тоже становятсяreadonly, а не только верхний уровень.- Это чисто компиляторная проверка: в рантайме объект остаётся обычным изменяемым JS-объектом,
readonlyне защищает от мутации черезasили сторонний код. - Нельзя применить к переменным, объявленным через
let, если хочется получить пользу — обычноas constсочетают сconst, иначе логика теряет смысл, хотя технически применить можно.
Итог
as const — простой и дешёвый способ получить более строгую типобезопасность без написания дополнительных интерфейсов: он сужает типы до литералов и делает данные неизменяемыми на уровне типов, что особенно полезно для конфигов, enum-подобных структур и строгих API.
Что хочет услышать интервьюер
Кандидат объясняет разницу между widening (расширением) типов и литеральными типами
Упоминает, что as const делает объект readonly, а массив — кортежем
Приводит пример практического применения: конфиги, статусы, экшены, роутинг
Понимает, что это только compile-time проверка, в рантайме объект остаётся изменяемым
Может показать связку as const с typeof и keyof для вывода union-типа
Пример: Widening без as const
// без as const тип расширяется до string
const role = "admin";
// TypeScript выводит тип: string
let method = "GET";
// тип: string, можно присвоить любую строку
method = "что угодно"; // не будет ошибки
Пример: Литеральные типы и readonly с as const
// тип выводится как литерал "admin", а не string
const role = "admin" as const;
const config = {
method: "GET",
retries: 3,
} as const;
// тип: { readonly method: "GET"; readonly retries: 3 }
config.method = "POST"; // ошибка компиляции: свойство readonly
Пример: Массив превращается в кортеж
const point = [10, 20] as const;
// тип: readonly [10, 20], а не number[]
function move([x, y]: readonly [number, number]) {
console.log(x, y);
}
move(point); // подходит, так как тип точно совпадает
Пример: Вывод union-типа из объекта
const ROLES = {
admin: "admin",
user: "user",
guest: "guest",
} as const;
// автоматически получаем union "admin" | "user" | "guest"
type Role = typeof ROLES[keyof typeof ROLES];
function setRole(role: Role) {
// ...
}
setRole(ROLES.admin); // ок
setRole("hacker"); // ошибка: не входит в union
Типичные ошибки
Путают as const с обычным приведением типа (type casting) as SomeType
Считают, что readonly от as const защищает данные в рантайме
Не знают, что as const превращает массив в кортеж фиксированной длины
Забывают, что as const применяется рекурсивно ко всем вложенным свойствам
Не могут привести пример, где as const реально решает проблему (например, вывод union из объекта)


