Перейти к основному содержимому

Классы в TypeScript

TypeScript добавляет к классам JavaScript типы и модификаторы видимости.

Эта страница предполагает, что вы уже знаете, как работают обычные классы JavaScript.


Члены класса: типы

Члены класса — его свойства и методы — получают типы с помощью аннотаций типов, точно так же как переменные.

Пример

name: string объявляет свойство, которое должно содержать текст.

Prompt
Покажите, что свойства класса типизируются аннотациями, как и переменные. Объявите класс Person со свойством name типа string, создайте экземпляр и присвойте его name значение "Jane". Пример ничего не печатает.
Вывод: программа на TypeScript и захваченный вывод

Члены класса: видимость

Члены класса могут также иметь специальные модификаторы, которые определяют, откуда к ним можно обращаться.

Примечание: В TypeScript есть три основных модификатора видимости.

  • public — (по умолчанию) к члену можно обращаться откуда угодно
  • private — к члену можно обращаться только внутри класса
  • protected — к члену можно обращаться из самого класса и из любого класса, который от него наследуется (см. разделы о наследовании ниже)

Примечание: Внутри класса ключевое слово this обычно указывает на текущий экземпляр класса.

Пример

Вызов getName() допустим, потому что метод публичный. Чтение person.name снаружи класса — ошибка компиляции, потому что name объявлен как private.

Prompt
Покажите модификаторы видимости private и public у членов класса. Объявите класс Person с private name: string, public конструктором, который его задаёт, и методом public getName(); создайте Person с именем "Jane", выведите getName() (это разрешено), затем выведите person.name напрямую, чтобы компилятор сообщил, что name объявлен как private и доступен только внутри класса.
Вывод: программа на TypeScript и захваченный вывод

Свойства-параметры

TypeScript предлагает сокращённый способ объявления членов класса в конструкторе: добавьте модификатор видимости к параметру конструктора, и он автоматически станет членом класса.

Пример

private name: string в конструкторе одновременно объявляет член name и присваивает ему значение — отдельная строка со свойством не нужна.

Prompt
Покажите свойства-параметры: объявление члена класса прямо в списке параметров конструктора. Объявите класс Person, конструктор которого принимает private name: string (с пустым телом), плюс метод public getName(), который его возвращает; создайте Person с именем "Jane" и выведите getName(), напечатав Jane.
Вывод: программа на TypeScript и захваченный вывод

Readonly

Как и в случае с массивами, ключевое слово readonly запрещает менять член класса после того, как он получил значение.

Пример

Член с readonly должен получить значение либо там, где он объявлен, либо в конструкторе, и после этого измениться не может.

Prompt
Покажите модификатор readonly у свойства класса. Объявите класс Person с private readonly name: string, задаваемым один раз в конструкторе (с комментарием, поясняющим, что после этого его нельзя изменить), и методом public getName(); создайте Person с именем "Jane" и выведите getName(), напечатав Jane.
Вывод: программа на TypeScript и захваченный вывод

Наследование: Implements

Интерфейс может описывать форму, которой должен следовать класс. Класс обещает ей соответствовать с помощью ключевого слова implements.

Примечание: Класс может реализовать несколько интерфейсов, перечислив их после implements через запятую, например class Rectangle implements Shape, Colored {

Пример

Rectangle обязан предоставить метод getArea, потому что этого требует интерфейс Shape.

Prompt
Покажите класс, реализующий интерфейс с помощью ключевого слова implements. Объявите интерфейс Shape со свойством-функцией getArea, возвращающим number, затем класс Rectangle, который его реализует, используя свойства-параметры protected readonly width и height и метод getArea(), возвращающий произведение ширины на высоту. Пример только объявляет и ничего не печатает.
Вывод: программа на TypeScript и захваченный вывод

Наследование: Extends

Класс может строиться на основе другого класса с помощью ключевого слова extends.

Класс может расширять только один другой класс.

Пример

Square расширяет Rectangle, передаёт в super одно и то же значение для ширины и высоты и наследует getArea, не записывая его заново.

Prompt
Покажите наследование классов с помощью ключевого слова extends. Объявите интерфейс Shape и класс Rectangle, который его реализует (protected readonly width и height, getArea(), возвращающий их произведение), а затем класс Square, который расширяет Rectangle и конструктор которого принимает один width и вызывает super(width, width), наследуя getArea. Пример только объявляет и ничего не печатает.
Вывод: программа на TypeScript и захваченный вывод

Override

Когда класс расширяет другой класс, он может заменить члены родителя, имеющие то же имя.

Более новые версии TypeScript позволяют отметить это явно ключевым словом override.

Примечание: По умолчанию ключевое слово override при переопределении метода необязательно; оно лишь помогает ловить ошибки, например «переопределение» метода, которого у родителя нет. Включите настройку noImplicitOverride, чтобы сделать его обязательным.

Пример

Square заменяет метод toString, унаследованный от Rectangle. Члены с protected по-прежнему доступны из Square.

Prompt
Покажите, как подкласс заменяет метод родителя, отмечая это ключевым словом override. Объявите интерфейс Shape, класс Rectangle, который его реализует, с protected readonly width и height, методом getArea() и методом toString(), возвращающим "Rectangle[width=..., height=...]", а затем подкласс Square, чей override toString() возвращает "Square[width=...]". Пример только объявляет и ничего не печатает.
Вывод: программа на TypeScript и захваченный вывод

Абстрактные классы

Класс можно написать так, чтобы он служил только основой для других классов, не реализуя все свои члены.

Это делается с помощью ключевого слова abstract у класса.

Члены, оставленные без реализации, тоже используют ключевое слово abstract.

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

Пример

Polygon оставляет getArea абстрактным, но реализует toString с его помощью. Rectangle расширяет Polygon и предоставляет недостающий getArea.

Prompt
Покажите абстрактный базовый класс с абстрактным методом, который должны реализовать подклассы. Объявите abstract class Polygon с public abstract getArea(): number и конкретным toString(), возвращающим "Polygon[area=...]", а затем класс Rectangle, который его расширяет, с protected readonly width и height, вызывает super() и реализует getArea(). Пример только объявляет и ничего не печатает.
Вывод: программа на TypeScript и захваченный вывод