Классы и new
До сих пор вы создавали объекты, записывая их целиком, { name: "Гоблин", health: 30 }, или с помощью функции, которая возвращает объект. Когда в игре нужно много однотипных объектов, в JavaScript есть другой способ: класс. Класс — это шаблон для объектов. Он один раз описывает, что будет у каждого созданного по нему объекта:
class Monster {
name: string = "Гоблин";
health: number = 30;
}
const goblin = new Monster();
const wolf = new Monster();
wolf.name = "Волк";
console.log(goblin);
console.log(wolf);Программа выводит:
Monster { name: "Гоблин", health: 30 }
Monster { name: "Волк", health: 30 }Разберём по шагам:
class Monster { … }объявляет класс с именемMonster. Имена классов начинаются с заглавной буквы, как и имена типов.- Внутри класса находятся его поля: свойства, которые будут у каждого объекта этого класса. Поле записывают как свойство в типе объекта: имя и тип, затем
=и начальное значение. Каждое поле заканчивается;. new Monster()создаёт из шаблона новый объект, у которого поля равны своим начальным значениям. Такой объект называют экземпляром класса. Каждыйnewсоздаёт отдельный объект, поэтому изменениеwolf.nameне затрагиваетgoblin.console.logпишет перед объектом имя его класса, так что видно, из чего объект создан.
Классы — часть JavaScript; TypeScript добавляет к ним типы полей. Как и у переменных, тип можно не указывать, если есть начальное значение: health = 30; — это number.
Класс — это ещё и тип. Имя Monster можно использовать в аннотациях, как типы из урока «Типы объектов»: const boss: Monster = new Monster(); или function hit(monster: Monster): void. TypeScript проверяет поля так же, как свойства: goblin.helth даёт Property 'helth' does not exist on type 'Monster'. Did you mean 'health'? (TS2551), а goblin.health = "много"; — это TS2322.
У каждого поля должно быть значение. Если не указать начальное значение, будет ошибка:
class Monster {
name: string = "Гоблин";
health: number;
}TypeScript сообщает:
main.ts(3,5): error TS2564: Property 'health' has no initializer and is not definitely assigned in the constructor.Без этой проверки у нового монстра в health лежало бы undefined, хотя по типу там number. В сообщении упоминается конструктор — другой способ дать полю значение; о нём в следующем упражнении.
Типичные ошибки:
- Забыли
new:const goblin = Monster();даётValue of type 'typeof Monster' is not callable. Did you mean to include 'new'?(TS2348). - Поле записано как свойство в литерале объекта:
name: "Гоблин";. После двоеточия идёт тип, поэтому"Гоблин"становится литеральным типом поля, значения у поля нет, и вы получаете TS2564. Значение пишут после=. - Поля разделены запятыми, как в объекте: TypeScript сообщает
';' expected.(TS1005).
Задание
- 1
Объявите класс
Monsterс двумя полями:name—stringс начальным значением"Гоблин"иhealth—numberс начальным значением30. - 2
Под классом создайте двух монстров через
new:goblinиwolf. Измените у волкаnameна"Волк", аhealthна25. Затем выведите обоих монстров:Monster { name: "Гоблин", health: 30 } Monster { name: "Волк", health: 25 } - 3
Напишите функцию
hit(monster: Monster, damage: number): void, которая уменьшает здоровье монстра наdamage. В конце программы вызовитеhit(wolf, 10)и выведите имя и здоровье волка так:Волк: 15