Назад | Учебник TypeScript | Вперёд
JavaScript использует прототипно-ориентированное программирование. В TypeScript всё более строго. Мы можем создавать строгие описания классов и создавать экземпляры классов, подчиняющиеся этому описанию.
Вы уже видели объявление классов в статье про первую программу на TypeScript. Ниже приведён пример простого класса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class MechWarrior { health : number; ammo : number; name : string; constructor(name: string) { this.name = name; } hit(damage: number) { this.health-=damage; if (this.health < 0) this.health = 0; } } let m:MechWarrior = new MechWarrior("Vasya"); |
Поддерживается иерархия классов и наследование:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Monster{ name: string; constructor(name:string) { this.name = name; } getName() { return "Monster: " + this.name; } } class Goblin extends Monster { getName() { return "Goblin: " + this.name; } } let a:Monster = new Monster("Alma"); let b:Monster = new Goblin("Vasya"); alert("a.getName() = " + a.getName()); // Monster: Alma alert("b.getName() = " + b.getName()); // Goblin: Vasya |
В этом примере мы объявили две переменные: a и b. Обе переменные имеют тип Monster. Первую переменную мы инициализировали экземпляром класса Monster, а вторую переменную инициализировали экземпляром класса Goblin. Теперь переменная b имеет тип Monster, но ссылается не на экземпляр Monster, а на экземпляр его наследника Goblin.
Класс Goblin наследует от Monster поле name и метод getName, но метод getName он переопределяет, поэтому при вызове getName у b будет вызван не метод класса Monster, а метод класса Goblin.
TypeScript поддерживает модификаторы доступа: private, protected и public.
Модификатор доступа private делает член класса доступным только внутри этого класса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Monster { health : number; private name: string; changeName(newName : string) { this.name = newName; // OK. Внутри класса // приватное поле доступно. } } let m:Monster = new Monster(); m.health = 100; // OK m.name = 'Vasya'; // Ошибка. Нельзя обращаться к приватному // полю снаружи от класса. |
Объявив поле с модификаторм private мы можем создать для доступа к нему getter-ы и setter-ы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Monster { health : number; private fieldName: string; get name() : string { return this.fieldName; } set name(newName : string) { this.fieldName = 'monster ' + newName; } } let m:Monster = new Monster(); m.health = 100; // OK m.name = 'Vasya'; // Здесь на самом деле вызывается // метод set name. alert(m.name); |
Внимание! Для поддержки getter-ов и setter-ов нужно компилировать с поддержкой ES5:
1 |
tsc monster.ts --target ES2016 |
Модификатор доступа protected позволяет получить доступ к полю только из этого класса и его наследников:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class Monster { health : number; protected name: string; changeName(newName : string) { this.name = newName; // OK. Внутри класса // protected полю доступно. } } class Goblin extends Monster { someMethod():string { return 'name: ' + name; // OK. В наследниках есть доступ // к полю с модификатором // protected } } let m:Monster = new Monster(); m.health = 100; // OK m.name = 'Vasya'; // Ошибка. Нельзя обращаться к protected // полю снаружи от класса. |
Модификатор доступа public указывать не обязательно, он используется по умолчанию. Он позволяет обращаться к полю абсолютно всем:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Monster { health : number; public name: string; // модификатор доступа public // здесь не обязателен changeName(newName : string) { this.name = newName; // OK. } } class Goblin extends Monster { someMethod():string { return 'name: ' + name; // OK. } } let m:Monster = new Monster(); m.health = 100; // OK m.name = 'Vasya'; // OK |
Модификатор readonly позволяет создать поля, значения которых нельзя менять. Они должны быть обязательно инициализированы при объявлении.
1 2 3 4 5 6 |
class Hexadaemon { readonly name :string = 'Hexadaemon monster'; readonly numberOfEyes : number = 12; } let v1 : Hexadaemon = new Hexadaemon(); |
Модификатор readonly можно указывать у параметро конструкторов. Тогда автоматически создаётся поле с именем, совпадающем с именем параметра, а внутри конструктора оно инициализируется значением с этого readonly параметра:
1 2 3 4 5 6 7 8 9 |
class Hexadaemon { readonly name :string = 'Hexadaemon monster'; constructor(readonly numberOfEyes: number) { } } let v1 : Hexadaemon = new Hexadaemon(13); alert(v1.numberOfEyes); |
Можно создавать статические поля с помощью ключевого поля static. Статические поля принадлежат не экземпляру класса, а всему классу. У всех экземпляров класса всегда одно и то же общее значение поля с модификатором static. Обращаться к статическому полю нужно не через имя экземпляра класса, а через имя класса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Monster { health : number; static totalMonstersCount: number = 0; constructor(health : number) { this.health = health; Monster.totalMonstersCount++; } } let m1 : Monster = new Monster(98); let m2 : Monster = new Monster(150); let m3 : Monster = new Monster(45); alert(Monster.totalMonstersCount); // 3 |
Можно создавать абстрактные классы. Абстактный класс — это класс, помеченный abstract. Нельзя создавать экземпляры абстрактных классов, они используются как базовые классы в иерархии. В абстрактные классы помещают общие методы, поля и объявления абстракнтых методов, которые должны реализовать дочерние классы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
abstract class Monster { health : number; // Just empty constructor constructor() { } // абстрактный метод abstract calculateDangerValue():number; // Дочерние классы // должны быть либо abstract, // либо содержать реализацию // абстрактных методов. monsterWithHealth() { return 'Monster ' + this.health; } } class Goblin extends Monster { constructor (health : number) { super(); this.health = health; } calculateDangerValue():number { return 1; } } // let v1:Monster = new Monster() // Нельзя let v2:Monster = new Goblin(100); // OK alert(v2.monsterWithHealth() + ' Danger '+ v2.calculateDangerValue()); |
Если вы до этого учили классы в языке программирования Java, то сказанное в этой статье должно быть для вас более чем понятно.