Перейти к содержимому
Теория · Объектные типы · урок 1 из 7

Тип объекта

Чему вы научитесь

Чему вы научитесь:

  • описывать форму объекта типом вроде { name: string; age: number };
  • давать типу имя через type и читать ошибки о недостающем свойстве;
  • объявлять необязательные свойства и проверять их перед использованием;
  • запрещать запись в свойство через readonly и знать, где эта защита кончается.
Бланк с полями name, необязательным age? с пунктирной рамкой и напечатанным id с замочком

Представьте бумажную анкету. На ней заранее напечатаны поля: «Имя», «Возраст». Сотрудник, который принимает анкету, проверяет две вещи: все ли поля заполнены и то ли в них написано. Если в поле «Возраст» стоит слово, а не число, анкету вернут на исправление.

В JavaScript такой проверки нет. Функция получает объект и надеется, что в нём есть нужные свойства. Если свойства нет, она молча получит undefined, и ошибка всплывёт позже, далеко от места, где её сделали.

В TypeScript у объекта есть своя анкета — тип объекта: список имён свойств и тип каждого из них. Компилятор сверяет с ним каждый объект, который вы передаёте:

TypeScript
function describe(user: { name: string; age: number }) {
    return `${user.name}, ${user.age}`;
}

console.log(describe({ name: "Ann", age: 30 })); // Ann, 30

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

  1. У параметра user тип { name: string; age: number }: в объекте должны быть свойство name со строкой и свойство age с числом.
  2. Внутри функции TypeScript знает форму user, поэтому user.name для него — string, а user.age — number.
  3. Вызов передаёт объект, который подходит под анкету, и программа печатает Ann, 30.

Как записать тип объекта

Тип объекта похож на сам объект, только справа от двоеточия стоят типы, а не значения. Разберём запись { name: string; age: number } по частям:

  • фигурные скобки открывают и закрывают описание формы;
  • name — имя свойства;
  • двоеточие и string — тип значения в этом свойстве;
  • точка с запятой отделяет свойства друг от друга; запятая тоже допустима, но в типах принято ставить точку с запятой.

Сравните две записи. { name: "Ann" } — объект со значением, он существует, пока работает программа. { name: string } — тип, описание формы: его видит только компилятор, и в JavaScript-файл он не попадёт.

Для объектного литерала TypeScript выводит тип сам. Например, после const user = { name: "Ann", age: 30 } редактор покажет у user тип { name: string; age: number; }, если навести на него курсор. Писать тип вручную приходится там, где выводить его не из чего, и чаще всего это параметр функции.

Не хватает свойства

Компилятор сверяет объект с анкетой целиком. Если обязательного свойства нет, он сообщает, какого именно:

TypeScript
const user: { name: string; age: number } = { name: "Ann" }; // ✗
TEXT
error TS2741: Property 'age' is missing in type '{ name: string; }' but required in type '{ name: string; age: number; }'.

Сообщение читается так: в типе { name: string; } нет свойства age, а в типе { name: string; age: number; } оно обязательно. Первый тип — это ваш литерал, каким его увидел TypeScript, второй — анкета из аннотации.

Если свойство на месте, но значение не того типа, ошибка будет другой — TS2322. Например, age: "30" не пройдёт: компилятор напишет, что строку нельзя присвоить типу number.

Здесь аналогия с анкетой перестаёт работать. Сотрудник смотрит и на сами ответы, а TypeScript проверяет только типы: возраст -5 он пропустит, ведь это число.

Опечатка в имени

Анкета защищает и при чтении: свойство, которого нет в типе, прочитать нельзя.

TypeScript
const user: { name: string; age: number } = { name: "Ann", age: 30 };
console.log(user.nmae); // ✗
TEXT
error TS2339: Property 'nmae' does not exist on type '{ name: string; age: number; }'.

В JavaScript эта строка напечатала бы undefined, и опечатку пришлось бы искать по странному выводу. TypeScript показывает её сразу и на той строке, где она сделана.

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

Параметру дали тип object, чтобы сказать «сюда передают объект»:

TypeScript
function greet(user: object) {
    return `Hi, ${user.name}`; // ✗
}

console.log(greet({ name: "Ann" }));
TEXT
error TS2339: Property 'name' does not exist on type 'object'.

Тип object значит «какой-то объект» и ничего не говорит о его свойствах. Это анкета без единого поля: по ней нельзя прочитать ни имя, ни возраст. Перечислите свойства, которые нужны функции: user: { name: string }.

Главное

  • Тип объекта перечисляет свойства и их типы: { name: string; age: number }.
  • Для объектного литерала TypeScript выводит такой тип сам, а у параметра функции его пишут вручную.
  • Нет обязательного свойства — ошибка TS2741; чтение свойства, которого нет в типе, — ошибка TS2339.
  • Тип object не называет свойств, поэтому читать их через него нельзя.