Перейти к содержимому
Теория · Аннотации и вывод типов · урок 6 из 9

let, const и литеральные типы

Помощник подписывает банки по содержимому. Но одну и ту же крупу он подпишет по-разному, если банки разные. Обычную банку открывают каждый день: сегодня в ней 200 граммов гречки, завтра — 150. На ней пишут общее «Гречка», а не точный вес. Запечатанную банку больше не откроют, поэтому на её наклейке можно написать точно: «Гречка, 200 г».

В TypeScript обычная банка — это let, а запечатанная — const:

TypeScript
let count = 5;
const limit = 5;
console.log(count + limit); // 10

Значение у обеих переменных одно и то же, а типы разные. Наведите курсор: над count подсказка покажет let count: number, а над limit — const limit: 5.

Литеральный тип

5 в подсказке над limit — не значение, а тип. Литеральный тип — это тип, у которого ровно одно значение: в переменную типа 5 можно положить только число 5. Такие типы называют по их значению: 5, "red", true.

Для константы это точное описание. Значение limit никогда не изменится, и TypeScript пишет на наклейке всё, что о нём знает.

Почему let расширяет тип

С let так не получится. Если бы let count = 5 получал тип 5, строка count = 6 стала бы ошибкой, и счётчик нельзя было бы увеличить. Поэтому TypeScript берёт общий тип, к которому относится значение: вместо 5 — number, вместо "red" — string. Такая замена называется расширением типа.

Расширение срабатывает и тогда, когда значение константы попадает в новую переменную let. У const brand = "red" тип "red", но let copy = brand снова получит string: новую переменную тоже могут изменить.

Здесь аналогия с банками заканчивается. На кухне видно, открывают банку или нет, а TypeScript не следит, меняется ли переменная на самом деле. Даже если count ни разу не получит нового значения, её тип останется number: решает слово в объявлении, let или const.

Нажимайте «Следующий шаг» и следите за подсказкой редактора: у let тип общий, у const — точный, а у свойства объекта — снова общий.

ВживуюКакой тип выводит TypeScriptшаг 1 из 7

У let общий тип number: позже в count можно записать другое число.

Сравните подсказку у let и у const

Тип зависит не только от значения, но и от того, может ли оно измениться: let получает общий тип, const — литеральный.

Объект в const

TypeScript
const point = { x: 5 };
point.x = 7;
console.log(point.x); // 7

const закрепляет только имя point: записать в него другой объект нельзя. А свойство x менять можно, поэтому TypeScript даёт ему общий тип. point получает тип { x: number; }, а не { x: 5; }. Так TypeScript записывает тип объекта: в фигурных скобках перечислены свойства и их типы, x: number — «свойство x имеет тип number».

Зачем нужен литеральный тип

Точный тип помогает компилятору находить бессмысленный код:

TypeScript
const limit = 5;
if (limit === 6) { // ✗
    console.log("шесть");
}
TEXT
error TS2367: This comparison appears to be unintentional because the types '5' and '6' have no overlap.

Сообщение значит: «сравнение выглядит случайным: у типов 5 и 6 нет общих значений». TypeScript знает, что в limit всегда 5, и равенство с 6 никогда не выполнится. С let limit = 5 ошибки не было бы: тип number допускает и 6.

На собеседовании любят спрашивать, почему у let и const с одним и тем же значением разные типы. Ответ — в изменяемости: let может получить новое значение, поэтому тип расширяется, а const — нет, поэтому тип остаётся литеральным.

Главное

  • Литеральный тип — тип с одним значением: 5, "red", true.
  • const limit = 5 получает литеральный тип 5: значение константы не изменится.
  • let count = 5 получает number: TypeScript расширяет тип, потому что переменная может измениться.
  • У объекта в const свойства получают общие типы: const point = { x: 5 } — это { x: number; }.