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

const и изменяемые объекты

Запечатанная банка const хранит одно значение, и TypeScript подписывает её точно. С числом всё ясно: const limit = 5 останется пятёркой навсегда. А что, если в константе лежит объект?

TypeScript
const cart = { total: 0 };
const scores = [3, 5];
cart.total = 1500;
scores.push(4);
console.log(cart.total, scores.length); // 1500 3

Программа компилируется без ошибок и печатает 1500 3. Давайте разберём её по строкам:

  1. const cart = { total: 0 }; — константа cart хранит объект со свойством total.
  2. const scores = [3, 5]; — константа scores хранит массив из двух чисел.
  3. cart.total = 1500; меняет свойство внутри объекта, и tsc не возражает.
  4. scores.push(4); добавляет элемент в тот же массив — тоже без ошибки.
  5. console.log печатает 1500 3: в total теперь 1500, а в массиве три элемента.

Объект и массив изменились, хотя оба объявлены через const. Что же тогда запрещает const?

Что запрещает const

const запрещает дать имени новое значение — записать в cart другой объект, даже точно такой же формы:

TypeScript
const cart = { total: 0 };
cart = { total: 1500 }; // ✗
TEXT
error TS2588: Cannot assign to 'cart' because it is a constant.

Сообщение значит: «нельзя присвоить cart новое значение, потому что это константа». В JavaScript эта строка упала бы только при запуске, с ошибкой TypeError: Assignment to constant variable. TypeScript находит её раньше — при компиляции.

Что можно менять внутри

Константа всё время держит одно и то же значение — один и тот же объект или массив. А то, что лежит внутри него, const не охраняет:

  • свойства объекта: cart.total = 1500;
  • элементы массива: scores[0] = 10;
  • методы, которые меняют массив: scores.push(4).

Здесь аналогия с запечатанной банкой заканчивается: она верна для чисел и строк, у которых нет частей. Объект больше похож на комод с ящиками. const намертво приклеивает наклейку cart к одному комоду, но ящики в нём по-прежнему выдвигаются.

Этот вопрос часто задают на собеседовании: «Можно ли изменить объект, объявленный через const?» Ответ: его свойства — можно, а записать в имя другой объект — нельзя.

Типы свойств остаются общими

Вы уже видели, что const point = { x: 5 } получает тип { x: number; }. С cart то же самое: его тип — { total: number; }. Поэтому в свойство можно записать любое другое число, но не значение другого типа:

TypeScript
const cart = { total: 0 };
cart.total = "бесплатно"; // ✗
TEXT
error TS2322: Type 'string' is not assignable to type 'number'.

const не охраняет содержимое объекта, а тип охраняет: менять total можно, но только на число.

Частая ошибка

Объявить через const значение, которое потом меняется целиком, например счётчик:

TypeScript
const attempts = 0;
attempts = attempts + 1; // ✗
TEXT
error TS2588: Cannot assign to 'attempts' because it is a constant.

attempts + 1 — новое число, и записать его в имя можно, только если оно объявлено через let. Исправление — let attempts = 0;. Правило выбора то же, что в JavaScript: const по умолчанию, let — когда имени дадут новое значение.

Главное

  • const запрещает дать имени новое значение: cart = … — ошибка TS2588.
  • Содержимое объекта и массива в const менять можно: свойства, элементы, push.
  • Типы свойств выводятся общими: в cart.total типа number можно записать другое число, но не строку.
  • Для значения, которое меняется целиком, например для счётчика, нужен let.