let, const и литеральные типы
Помощник подписывает банки по содержимому. Но одну и ту же крупу он подпишет по-разному, если банки разные. Обычную банку открывают каждый день: сегодня в ней 200 граммов гречки, завтра — 150. На ней пишут общее «Гречка», а не точный вес. Запечатанную банку больше не откроют, поэтому на её наклейке можно написать точно: «Гречка, 200 г».
В TypeScript обычная банка — это let, а запечатанная — const:
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 — точный, а у свойства объекта — снова общий.
1let count = 5;подсказка редактораcount: number2const limit = 5;3let color = "red";4const brand = "red";5let copy = brand;6const point = { x: 5 };7point.x = 7;
У let общий тип number: позже в count можно записать другое число.
Тип зависит не только от значения, но и от того, может ли оно измениться: let получает общий тип, const — литеральный.
Объект в const
const point = { x: 5 };
point.x = 7;
console.log(point.x); // 7const закрепляет только имя point: записать в него другой объект нельзя. А свойство x менять можно, поэтому TypeScript даёт ему общий тип. point получает тип { x: number; }, а не { x: 5; }. Так TypeScript записывает тип объекта: в фигурных скобках перечислены свойства и их типы, x: number — «свойство x имеет тип number».
Зачем нужен литеральный тип
Точный тип помогает компилятору находить бессмысленный код:
const limit = 5;
if (limit === 6) { // ✗
console.log("шесть");
}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; }.