TypeScript 1.6: Классы

В JavaScript на практике часто используют два общих паттерна проектирования: паттерн “Модуль” и паттерн “Класс”. Если не вдаваться в детали, то можно говорить, что паттерн “Модуль” использует замыкания для сокрытия имен и инкапсуляции данных. Паттерн “Класс” использует цепочки прототипов для реализации множества вариантов объектно-ориентированных механизмов наследования. Пространства имен языка TypeScript являются формализацией паттерна “Модуль”. (На самом деле терминология паттерна “Модуль” в настоящее время несколько неудачна, поскольку ECMAScript 2015 поддерживает модули несколько иным способом, нежели сам паттерн. По этой причине TypeScript использует термин “пространство имен” для формализации этого паттерна.)

Рассмотрим пример простого класса, написанного на TypeScript:

class BankAccount { 
balance = 0;
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}

При компиляции получим следующий JavaScript код:

var BankAccount = (function () { 
function BankAccount() {
this.balance = 0;
}
BankAccount.prototype.deposit = function(credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();

Данное объявление класса TypeScript создает переменную с именем ‘BankAccount’, значением которой является функция-конструктор для создания экземпляров данного класса. В данном объявлении также создается тип экземпляра с тем же самым именем. Если представить данный тип в виде интерфейса, то он будет выглядеть следующим образом:

interface BankAccount { 
balance: number;
deposit(credit: number): number;
}

Объявление типа функции для конструктора ‘BankAccount’ будет иметь следующий вид:

var BankAccount: new() => BankAccount;

Сигнатура функции использует префикс с ключевым словом new(), который означает, что функция ‘BankAccount’ должна быть вызвана как конструктор. Тип функции может иметь одновременно сигнатуры обычного вызова и конструктора. Например, объект Date включает в себя оба типа сигнатур.

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

If we want to start our bank account with an initial balance, we can add to the ‘BankAccount’ class a constructor declaration.

class BankAccount { 
balance = 0;
constructor(initially: number) {
this.balance = initially;
}

deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}

В данном примере при создании экземпляра класса ‘BankAccount’ нужно передать в конструктор параметр, значение которого будет присвоено полю balance. Также можно использовать более короткую запись:

class BankAccount { 
constructor(public balance: number) { }
deposit(credit: number) {
this.balance += credit;
return this.balance;
}
}

Ключевое слово ‘public’ означает, что параметр конструктора является полем класса. ‘public’ используется по умолчанию для членов класса, но также для поля можно задать доступность поля private или protected. Доступность поля является конструкцией времени разработки; она используется во время статической проверки типов, но не во время выполнения.

TypeScript классы также поддерживают наследование:

class CheckingAccount extends BankAccount { 
constructor(balance: number) {
super(balance);
}
writeCheck(debit: number) {
this.balance -= debit;
}
}

В данном примере класс ‘CheckingAccount’ является наследником класса ‘BankAccount’. Конструктор класса ‘CheckingAccount’ вызывает конструктор класса ‘BankAccount’ с помощью ключевого слова ‘super’. В полученном после компиляции JavaScript коде прототип ‘CheckingAccount’ будет являться цепочкой прототипа ‘BankAccount’.

Классы в TypeScript также могут содержать статические члены. Статические члены класса становятся свойствами конструктора класса.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.