Лишние свойства в литерале
Ключ можно заказать у мастера по описанию. Если в заказе указан зубец, для которого в замке нет выемки, мастер переспросит: скорее всего, вы ошиблись, когда диктовали заказ. А готовый ключ, принесённый из дома, он только примерит и не станет спрашивать, зачем на нём брелок.
Так же TypeScript относится к объектам. Возьмём функцию, которая рисует линию по настройкам. Цвет обязателен, толщину можно не указывать — тогда она будет 1:
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Давайте разберём пример по строкам:
- В
Optionsсвойствоcolorобязательно, аwidthпомечено?. drawберёт толщину из настроек, а если её нет, подставляет1через??.- Первый вызов печатает
red line, 3px, второй —blue line, 1px.
Представьте, что в слове width сделали опечатку. В JavaScript объект { color: "red", widht: 3 } молча пройдёт: функция не найдёт width и нарисует линию толщиной 1. Ошибку пришлось бы искать по странной картинке.
Что видит tsc в литерале
Объектный литерал, написанный прямо там, где ждут Options, tsc сверяет с типом в обе стороны: все ли обязательные свойства на месте и нет ли лишних. Это и есть проверка лишних свойств. Попробуем два литерала с лишним свойством:
interface Options {
color: string;
width?: number;
}
const wide: Options = { color: "red", size: 3 }; // ✗
const typo: Options = { color: "red", widht: 3 }; // ✗Сообщения для двух строк разные.
Неизвестное свойство
error TS2353: Object literal may only specify known properties, and 'size' does not exist in type 'Options'.Сообщение значит: «в объектном литерале можно указывать только известные свойства, а size в типе Options нет». Свойства с похожим именем в типе нет, поэтому tsc называет лишнее, и всё.
Похожее имя
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 почти совпадает с настоящим свойством, и подсказывает исправление. Ради таких опечаток проверка и существует.
Через переменную проверки нет
Тот же объект с лишним свойством, сохранённый сначала в переменную, проходит:
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, литерал вынесли в переменную:
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…». - Объект из переменной сравнивается только по форме, и лишние свойства в нём не мешают.
- Вынести литерал в переменную, чтобы ошибка пропала, — значит спрятать опечатку; тип указывают там, где объект создают.