TypeScriptでクラスを使う機会が増えてきたので、改めてクラスについて整理します。
TypeScript Deep Diveのクラスのページを参考に、試しながらまとめてみたいと思います。
今回は練習として、飲み物クラスと紅茶クラスを作ってみます。
クラス
簡単なクラス定義
飲み物クラスDrink
を作りました。
type Temperture = 'hot' | 'cold';
class Drink {
temperature: Temperture;
constructor(temperature: Temperture) {
this.temperature = temperature;
}
}
const hotDrink = new Drink('hot');
console.log(hotDrink.temperature);// hot
クラスのメンバ変数として温度temperature
を設定できるようにしました。
あったかい飲み物が作れました。
コンストラクタの省略
コンストラクタは省略可能です。
なので温度のメンバ変数を作らず、単にDrinkクラスを作ることができます。
メンバ定義の省略
また、メンバ変数の定義を省略することができます。
コンストラクタの引数にアクセス修飾子(後述)を指定でき、自動的にクラス内に宣言され、値もコンストラクタの引数によって初期化されます。
以下の記述で、最初のクラス定義と同様の内容となります。
type Temperture = 'hot' | 'cold';
class Drink {
constructor(temperature: Temperture) {} // 代入しなくて良い
}
const hotDrink = new Drink('hot');
console.log(hotDrink.temperature);// hot
継承
extends
を使うことで継承ができます。
飲み物クラスを継承して紅茶クラスを作ってみます。
class Tea extends Drink {
constructor(public temperature: Temperture, public brand: string) {
super(temperature);
}
}
const tea = new Tea('hot', 'assam');
console.log(tea.temperature); // hot
console.log(tea.brand); // assam
継承したクラスにconstructorをつける場合は、コンストラクタで継承元(親)コンストラクタを呼び出す必要があります。
super
で親コンストラクタのメンバ変数temperature
をオーバーライドすると、子クラスで新たな処理を追加することができます。
今回は紅茶の銘柄を設定できるようにしました。
あったかいアッサムティーができました。
静的メンバ
static
プロパティのメンバ変数は、クラスの全てのインスタンスで共有されます。
クラス名.メンバ名
でアクセスできます。
試してみましょう。
type Temperture = 'hot' | 'cold';
class Drink {
static num: number = 0;
constructor(public temperature: Temperture) {
Drink.num++;
}
}
class Tea extends Drink {
constructor(public temperature: Temperture, public brand: string) {
super(temperature);
}
}
const tea1 = new Tea('hot', 'assam');
const tea2 = new Tea('cold', 'darjeeling');
console.log(tea1.brand); // assam
console.log(tea2.brand); // darjeeling
console.log(Tea.num); // 2
console.log(Drink.num); // 2
飲み物クラスに生成された数num
メンバを追加しました。
コンストラクタで毎回プラスされます。
紅茶クラスは飲み物クラスを継承しているのでnum
にアクセスすることができます。
あたたかいアッサムティーと冷たいダージリンティーを作りました。
それぞれ飲み物としては別物ですが、飲み物クラスのインスタンス数がクラス内で共有されるので、飲み物は2つ、となりますね。
アクセス修飾子
TypeScriptではpublic
、 private
、 protected
がサポートされています。
メンバ変数とメンバ関数に使用することができます。
public
はどこからでもアクセス可能です。
同一クラス、クラスから継承した子クラス、インスタンスとなってもアクセスができます。
private
は同一クラス内でのみアクセス可能です。
protected
は同一クラス、クラスから継承した子クラスはアクセスできますが、インスタンスではアクセスできません。
アクセス修飾子が指定されていない場合は、暗黙的にpublic
となります。
試してみましょう。
type Temperture = 'hot' | 'cold';
class Drink {
name: string = 'hoge';
private capacityMl: number = 500;
protected price: number = 600;
static num: number = 0;
constructor(public temperature: Temperture) {
Drink.num++;
console.log('Drink:', this.name);
console.log('Drink:', this.capacityMl);
console.log('Drink:', this.price);
}
}
class Tea extends Drink {
constructor(public temperature: Temperture, public brand: string) {
super(temperature);
console.log('Tea:', this.name);
console.log('Tea:', this.capacityMl); // プロパティ 'capacityMl' はプライベートで、クラス 'Drink' 内でのみアクセスできます。ts(2341)
console.log('Tea:', this.price);
}
}
const drink1 = new Drink('hot');
console.log('drink1:', drink1.name);
console.log('drink1:', drink1.capacityMl); // プロパティ 'capacityMl' はプライベートで、クラス 'Drink' 内でのみアクセスできます。ts(2341)
console.log('drink1:', drink1.price); // プロパティ 'price' は保護されているため、クラス 'Drink' とそのサブクラス内でのみアクセスできます。ts(2445)
const tea1 = new Tea('hot', 'assam');
console.log('tea1:', tea1.name);
// console.log('tea1:', tea1.capacityMl); // プロパティ 'capacityMl' はプライベートで、クラス 'Drink' 内でのみアクセスできます。ts(2341)
console.log('tea1:', tea1.price); // プロパティ 'price' は保護されているため、クラス 'Drink' とそのサブクラス内でのみアクセスできます。ts(2445)
飲み物クラスに
publicメンバ変数name
、privateメンバ変数capacityMl
、protectedメンバ変数price
を追加しました。
飲み物の名前、容量、値段、を設定できるイメージです。
まず、飲み物クラスのコンストラクタ内で全てのメンバ変数にアクセスしたところ、全てアクセスできました。
次に、紅茶クラスのコンストラクタ内で全てのメンバ変数にアクセスしたところ、capacityMl
はアクセス時にエラーとなりました。
private
なので親クラス以外からはアクセスできないのがわかります。
最後に飲み物クラスと紅茶クラスをインスタンス化したものからアクセスしました。
どちらもcapacityMl
、protected
はアクセス時にエラーとなりました。
先ほど同様、capacityMl
はprivate
なので親クラス以外からはアクセスできないのがわかります。
また、price
はprotected
なので、子クラスではアクセスできますが、インスタンスからはアクセスできないことがわかります。
また、全てのパターンでname
にアクセスができたので、暗黙的にpublic
になっていることがわかりました。
実際に動かしてみるとよくわかりますね。
まとめ
TypeScriptでクラスについてまとめていきました。
抽象クラスについてはまた後日描いてみたいと思います。
コメント