はじめに
この記事では、TypeScript におけるクラスと継承について解説します。
この記事でわかること
- クラスの定義の仕方
- クラスの継承の仕方
クラスの定義
クラスは主に 3 つの要素で構成される。
- プロパティ: クラスが持つデータ。TypeScript では、プロパティごとに型を明記する。
- コンストラクタ: クラスからインスタンスを作成する際に一度だけ呼ばれる特別なメソッド。主にプロパティの初期化に使われる。
- メソッド: クラスが持つ振る舞い。
class Person {
// プロパティの定義
name: string;
age: number;
// コンストラクの定義
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// メソッドの定義
greet(): string {
return `こんにちは、${this.name}です。${this.age}歳です。`;
}
}
// クラスからインスタンスを作成
const taro = new Person("太郎", 23);
const tom = new Person("トム", 30);
// メソッドの呼び出し
console.log(taro.greet()); // "こんにちは、太郎です。23歳です。"
console.log(tom.greet()); // "こんにちは、トムです。30歳です。"
// プロパティへのアクセス
console.log(taro.name); // "太郎"
アクセス修飾子
プロパティやメソッドが、クラスの「どこから」アクセスできるかを制御します。
-
public (デフォルト):
-
クラスの内部、外部、どこからでもアクセスできます。
-
何も指定しない場合は public になります。
-
-
private:
- そのクラスの内部からのみアクセスできます。インスタンス(外部)からはアクセスできません。
-
protected:
- そのクラスの内部、またはそのクラスを継承した子クラスからのみアクセスできます。
class Person {
public name: string;
private age: number; // クラス内部でのみ利用
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public greet(): string {
return `こんにちは、${this.name}です。${this.age}歳です。`;
}
}
const taro = new Person("太郎", 23);
console.log(taro.name); // "太郎" (publicなのでOK)
console.log(taro.greet()); // "こんにちは、太郎です。23歳です。" (publicメソッド経由でprivateなageを利用)
console.log(taro.age); // エラー! "age" は private で、Person クラスの外部からはアクセスできません。
省略記法
TypeScript では、コンストラクタの引数にアクセス修飾子をつけることで、プロパティの宣言と初期化を同時に行う省略記法が使えます。
class Person {
constructor(public name: string, public age: number) {}
greet(): string {
return `こんにちは、${this.name}です。${this.age}歳です。`;
}
}
クラスの継承
継承は、既存のクラス(親クラスまたはスーパークラス)の機能(プロパティやメソッド)を引き継いで、新しいクラス(子クラスまたはサブクラス)を作成する仕組みです。
-
extends: クラスを継承することを示します。 -
super(): 子クラスのコンストラクタ内で、親クラスのコンストラクタを呼び出すために必ず使います。 - オーバーライド: 親クラスのメソッドを、子クラスで同じ名前で再定義(上書き)することです。
// 親クラス (スーパークラス)
class Vehicle {
constructor(protected speed: number) {}
move(): void {
console.log(`時速 ${this.speed} kmで移動します。`);
}
}
// 子クラス (サブクラス)
class Car extends Vehicle {
private engineName: string;
constructor(speed: number, engineName: string) {
// 親クラスのコンストラクタを呼び出す (super)
super(speed);
// 子クラス独自の初期化
this.engineName = engineName;
}
// メソッドのオーバーライド
move(): void {
console.log(
`${this.engineName} エンジンを搭載し、時速 ${this.speed} kmで走行します。`
);
}
// 子クラス独自のメソッド
honk(): void {
console.log("クラクションを鳴らします!");
}
}
const myCar = new Car(60, "V8");
myCar.move(); // "V8 エンジンを搭載し、時速 60 kmで走行します。" (オーバーライドされたメソッド)
myCar.honk(); // "クラクションを鳴らします!" (子クラス独自のメソッド)
const myVehicle = new Vehicle(30);
myVehicle.move(); // "時速 30 kmで移動します。" (親クラスのメソッド)