TypeScript
クラス
サーチ…
前書き
TypeScriptは、ECMA Script 6と同様に、クラスを使用したオブジェクト指向プログラミングをサポートしています。これは、プロトタイプベースの継承チェーンのみをサポートしていた古いJavaScriptバージョンとは対照的です。
TypeScriptのクラスサポートは、クラスが他のクラスを継承し、オブジェクトはクラスインスタンスとしてインスタンス化されますが、JavaやC#などの言語のクラスサポートと似ています。
これらの言語と同様に、TypeScriptクラスはインタフェースを実装したり、ジェネリックを利用することができます。
シンプルなクラス
class Car {
public position: number = 0;
private speed: number = 42;
move() {
this.position += this.speed;
}
}
この例では、単純なクラスのCar
を宣言します。クラスには3つのメンバーがあります:プライベート・プロパティspeed
、パブリックプロパティ・position
、パブリックメソッド・move
。各メンバーはデフォルトで公開されています。だから私たちがpublic
キーワードを使わなかったとしても、 move()
がpublicである理由です。
var car = new Car(); // create an instance of Car
car.move(); // call a method
console.log(car.position); // access a public property
基本的な継承
class Car {
public position: number = 0;
protected speed: number = 42;
move() {
this.position += this.speed;
}
}
class SelfDrivingCar extends Car {
move() {
// start moving around :-)
super.move();
super.move();
}
}
この例は、 extends
キーワードを使用してCar
クラスの非常に単純なサブクラスを作成する方法を示しています。 SelfDrivingCar
クラスには、オーバーライドmove()
メソッドを使用し、基本クラスimplementionを使用するsuper
。
コンストラクタ
この例では、 constructor
を使用して、基本クラスのパブリックプロパティのposition
と保護されたプロパティのspeed
を宣言します。これらのプロパティはパラメータプロパティと呼ばれます 。それらは、1つの場所にコンストラクタパラメータとメンバを宣言します。
TypeScriptの中で最高のものの1つは、コンストラクタパラメータを関連するプロパティに自動的に割り当てることです。
class Car {
public position: number;
protected speed: number;
constructor(position: number, speed: number) {
this.position = position;
this.speed = speed;
}
move() {
this.position += this.speed;
}
}
このコードはすべて単一のコンストラクタで再開できます。
class Car {
constructor(public position: number, protected speed: number) {}
move() {
this.position += this.speed;
}
}
そして、どちらもTypeScript(デザインタイムとコンパイル時間)から同じ結果でJavaScriptに変換されますが、コードは大幅に少なくなります:
var Car = (function () {
function Car(position, speed) {
this.position = position;
this.speed = speed;
}
Car.prototype.move = function () {
this.position += this.speed;
};
return Car;
}());
派生クラスのコンストラクタは、基本クラスのコンストラクタをsuper()
で呼び出さなければなりません。
class SelfDrivingCar extends Car {
constructor(startAutoPilot: boolean) {
super(0, 42);
if (startAutoPilot) {
this.move();
}
}
}
let car = new SelfDrivingCar(true);
console.log(car.position); // access the public property position
アクセサリー
この例では、「Simpleクラス」の例を変更してspeed
プロパティにアクセスできるようにします。 Typescriptアクセサを使用すると、getterまたはsetterにコードを追加できます。
class Car {
public position: number = 0;
private _speed: number = 42;
private _MAX_SPEED = 100
move() {
this.position += this._speed;
}
get speed(): number {
return this._speed;
}
set speed(value: number) {
this._speed = Math.min(value, this._MAX_SPEED);
}
}
let car = new Car();
car.speed = 120;
console.log(car.speed); // 100
抽象クラス
abstract class Machine {
constructor(public manufacturer: string) {
}
// An abstract class can define methods of it's own, or...
summary(): string {
return `${this.manufacturer} makes this machine.`;
}
// Require inheriting classes to implement methods
abstract moreInfo(): string;
}
class Car extends Machine {
constructor(manufacturer: string, public position: number, protected speed: number) {
super(manufacturer);
}
move() {
this.position += this.speed;
}
moreInfo() {
return `This is a car located at ${this.position} and going ${this.speed}mph!`;
}
}
let myCar = new Car("Konda", 10, 70);
myCar.move(); // position is now 80
console.log(myCar.summary()); // prints "Konda makes this machine."
console.log(myCar.moreInfo()); // prints "This is a car located at 80 and going 70mph!"
抽象クラスは、他のクラスを拡張できる基底クラスです。インスタンス化することはできません(つまり、 new Machine("Konda")
実行することはできません)。
Typescriptの抽象クラスの2つの重要な特性は次のとおりです。
- 彼らは独自のメソッドを実装できます。
- 継承クラスで実装する必要があるメソッドを定義できます。
このため、抽象クラスは概念的にはインタフェースとクラスの組み合わせと見なすことができます 。
モンキーは関数を既存のクラスにパッチする
時々、新しい関数でクラスを拡張できることは有益です。たとえば、文字列をラクダの文字列に変換する必要があるとします。 string
を返すtoCamelCase
という関数がString
含まれていることをTypeScriptに伝える必要がありstring
。
interface String {
toCamelCase(): string;
}
これで、この関数をString
実装にパッチすることができます。
String.prototype.toCamelCase = function() : string {
return this.replace(/[^a-z ]/ig, '')
.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, (match: any, index: number) => {
return +match === 0 ? "" : match[index === 0 ? 'toLowerCase' : 'toUpperCase']();
});
}
このString
拡張がロードされた場合、次のように使用できます。
"This is an example".toCamelCase(); // => "thisIsAnExample"
トランスレーション
SomeClass
クラスを考えると、TypeScriptがどのようにJavaScriptに変換されるかを見てみましょう。
TypeScriptソース
class SomeClass {
public static SomeStaticValue: string = "hello";
public someMemberValue: number = 15;
private somePrivateValue: boolean = false;
constructor () {
SomeClass.SomeStaticValue = SomeClass.getGoodbye();
this.someMemberValue = this.getFortyTwo();
this.somePrivateValue = this.getTrue();
}
public static getGoodbye(): string {
return "goodbye!";
}
public getFortyTwo(): number {
return 42;
}
private getTrue(): boolean {
return true;
}
}
JavaScriptソース
TypeScript v2.2.2を使用してv2.2.2
と、出力は次のようになります。
var SomeClass = (function () {
function SomeClass() {
this.someMemberValue = 15;
this.somePrivateValue = false;
SomeClass.SomeStaticValue = SomeClass.getGoodbye();
this.someMemberValue = this.getFortyTwo();
this.somePrivateValue = this.getTrue();
}
SomeClass.getGoodbye = function () {
return "goodbye!";
};
SomeClass.prototype.getFortyTwo = function () {
return 42;
};
SomeClass.prototype.getTrue = function () {
return true;
};
return SomeClass;
}());
SomeClass.SomeStaticValue = "hello";
観察
- クラスのプロトタイプの修正は、 IIFEの中にラップされています 。
- メンバ変数は、メインクラス
function
内で定義されfunction
。 - 静的プロパティはクラスオブジェクトに直接追加され、インスタンスプロパティはプロトタイプに追加されます。