Перейти к содержимому
Теория · Интерфейсы и структурная типизация · урок 7 из 12

Лишние свойства в литерале

Ключ можно заказать у мастера по описанию. Если в заказе указан зубец, для которого в замке нет выемки, мастер переспросит: скорее всего, вы ошиблись, когда диктовали заказ. А готовый ключ, принесённый из дома, он только примерит и не станет спрашивать, зачем на нём брелок.

Так же TypeScript относится к объектам. Возьмём функцию, которая рисует линию по настройкам. Цвет обязателен, толщину можно не указывать — тогда она будет 1:

TypeScript
interface Options {
    color: string;
    width?: number;
}

function draw(opts: Options): string {
    return `${opts.color} line, ${opts.width ?? 1}px`;
}

console.log(draw({ color: "red", width: 3 })); // red line, 3px
console.log(draw({ color: "blue" })); // blue line, 1px

Давайте разберём пример по строкам:

  1. В Options свойство color обязательно, а width помечено ?.
  2. draw берёт толщину из настроек, а если её нет, подставляет 1 через ??.
  3. Первый вызов печатает red line, 3px, второй — blue line, 1px.

Представьте, что в слове width сделали опечатку. В JavaScript объект { color: "red", widht: 3 } молча пройдёт: функция не найдёт width и нарисует линию толщиной 1. Ошибку пришлось бы искать по странной картинке.

Что видит tsc в литерале

Объектный литерал, написанный прямо там, где ждут Options, tsc сверяет с типом в обе стороны: все ли обязательные свойства на месте и нет ли лишних. Это и есть проверка лишних свойств. Попробуем два литерала с лишним свойством:

TypeScript
interface Options {
    color: string;
    width?: number;
}

const wide: Options = { color: "red", size: 3 }; // ✗
const typo: Options = { color: "red", widht: 3 }; // ✗

Сообщения для двух строк разные.

Неизвестное свойство

TEXT
error TS2353: Object literal may only specify known properties, and 'size' does not exist in type 'Options'.

Сообщение значит: «в объектном литерале можно указывать только известные свойства, а size в типе Options нет». Свойства с похожим именем в типе нет, поэтому tsc называет лишнее, и всё.

Похожее имя

TEXT
error TS2561: Object literal may only specify known properties, but 'widht' does not exist in type 'Options'. Did you mean to write 'width'?

Здесь код ошибки другой — TS2561, и в конце tsc спрашивает: «Может быть, вы хотели написать width?» Он заметил, что widht почти совпадает с настоящим свойством, и подсказывает исправление. Ради таких опечаток проверка и существует.

Через переменную проверки нет

Тот же объект с лишним свойством, сохранённый сначала в переменную, проходит:

TypeScript
interface Options {
    color: string;
    width?: number;
}

function draw(opts: Options): string {
    return `${opts.color} line, ${opts.width ?? 1}px`;
}

const style = { color: "red", width: 3, dashed: true };
console.log(draw(style)); // red line, 3px

У style своя форма, и она может пригодиться где-то ещё: например, другой функции нужен dashed. Поэтому для draw действует обычное правило формы: нужные свойства есть, а лишнее не мешает. Как мастер с ключом из дома: брелок ему не помеха.

Проверку лишних свойств получает только свежий литерал — объект, написанный прямо там, где tsc сверяет его с типом. Чаще всего это два места:

  • справа от = в объявлении с типом: const o: Options = { … };
  • аргумент вызова: draw({ … }).

Почему литерал с лишним свойством не проходит, а тот же объект из переменной проходит, часто спрашивают на собеседовании.

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

Чтобы убрать ошибку TS2561, литерал вынесли в переменную:

TypeScript
interface Options {
    color: string;
    width?: number;
}

function draw(opts: Options): string {
    return `${opts.color} line, ${opts.width ?? 1}px`;
}

const style = { color: "red", widht: 3 };
console.log(draw(style)); // ✗

Компилятор промолчит, и программа напечатает red line, 1px: опечатка никуда не делась, но tsc её больше не видит. Правильнее исправить имя свойства, а если объект нужно хранить в переменной, указать тип там, где объект создают: const style: Options = { color: "red", widht: 3 };. Тогда литерал снова свежий, и tsc покажет TS2561 на нужной строке.

Главное

  • Свежий литерал — объект, написанный прямо там, где его сверяют с типом, — tsc проверяет на лишние свойства.
  • Лишнее свойство — ошибка TS2353, а похожее на настоящее — TS2561 с подсказкой «Did you mean…».
  • Объект из переменной сравнивается только по форме, и лишние свойства в нём не мешают.
  • Вынести литерал в переменную, чтобы ошибка пропала, — значит спрятать опечатку; тип указывают там, где объект создают.