TypeScript 抽象メソッド解説
TypeScriptで抽象メソッドを宣言する
TypeScriptでは、抽象クラス (abstract class) 内で抽象メソッド (abstract method) を宣言することができます。抽象メソッドは、そのクラスのサブクラスで実装されるべきメソッドであり、自身では実装されないため、メソッド本体は空のままです。
抽象メソッドの宣言方法
abstract class Shape {
abstract getArea(): number;
}
この例では、Shape
という抽象クラスを定義し、その中にgetArea()
という抽象メソッドを宣言しています。getArea()
メソッドは、Shape
クラスのサブクラスで実装されるべきメソッドであり、Shape
クラス自身では実装されません。
抽象クラスのサブクラスで抽象メソッドを実装
class Circle extends Shape {
constructor(public radius: number) {
super();
}
getArea(): number {
return Math.PI * this.radius * this.radius;
}
}
Circle
クラスはShape
クラスを継承し、getArea()
メソッドを実装しています。Circle
クラスのgetArea()
メソッドは、円の面積を計算し、その結果を返します。
抽象メソッドの利点
- 強制的な実装
サブクラスは、抽象メソッドを実装しなければなりません。 - コードの再利用性
抽象クラスとサブクラスを用いて、コードを再利用することができます。 - 共通インターフェースの定義
抽象メソッドは、サブクラスで共通のインターフェースを定義することができます。
TypeScript 抽象メソッド解説: コード例
抽象クラスの定義と抽象メソッドの宣言
abstract class Animal {
abstract makeSound(): void;
}
makeSound()
という抽象メソッドを宣言します。このメソッドは、Animal
クラスのサブクラスで実装されるべきメソッドであり、Animal
クラス自身では実装されません。Animal
という抽象クラスを定義します。
class Dog extends Animal {
makeSound(): void {
console.log("ワンワン");
}
}
class Cat extends Animal {
makeSound(): void {
console.log("ニャー");
}
}
- 両クラスとも
makeSound()
メソッドを実装しています。それぞれのクラスは、異なる動物の鳴き声を表現します。 Dog
とCat
というクラスがAnimal
クラスを継承します。
function makeAnimalsSound(animals: Animal[]) {
for (const animal of animals) {
animal.makeSound();
}
}
const animals: Animal[] = [new Dog(), new Cat()];
makeAnimalsSound(animals);
- 各動物の
makeSound()
メソッドが呼び出され、それぞれの鳴き声がコンソールに出力されます。 Dog
とCat
のインスタンスを配列に格納し、makeAnimalsSound()
関数に渡します。makeAnimalsSound()
という関数では、Animal
型の配列を受け取り、各動物の鳴き声を呼び出します。
このコード例では、以下のことがわかります
- 抽象メソッドは、ポリモーフィズムを実現するのに役立ちます。
- 抽象メソッドは、共通のインターフェースを定義し、サブクラスで実装を強制することができます。
さらに、以下の点にも注意してください
- サブクラスは、抽象クラスのすべての抽象メソッドを実装しなければなりません。
- 抽象クラスは、少なくとも1つの抽象メソッドを持つ必要があります。
- 抽象メソッドは、メソッド本体を持たず、セミコロンで終わります。
- 抽象メソッドは、
abstract
キーワードを使用して宣言されます。
インターフェースの使用
interface Animal {
makeSound(): void;
}
class Dog implements Animal {
makeSound(): void {
console.log("ワンワン");
}
}
class Cat implements Animal {
makeSound(): void {
console.log("ニャー");
}
}
- クラスがインターフェースを実装することで、そのクラスはインターフェースで定義されたメソッドを実装しなければなりません。
- インターフェース (interface) を定義し、メソッドのシグネチャを指定します。
型ガードの使用
function makeAnimalSound(animal: { makeSound: () => void }) {
if (animal.makeSound) {
animal.makeSound();
}
}
- メソッドが存在する場合にのみ、そのメソッドを呼び出すことができます。
- 型ガード (type guard) を使用して、オブジェクトが特定のメソッドを持っているかどうかをチェックします。
ユーティリティ型の使用
type Animal = {
makeSound: () => void;
};
function makeAnimalSound(animal: Animal) {
animal.makeSound();
}
- ユーティリティ型を用いて、メソッドのシグネチャを指定することができます。
- ユーティリティ型 (utility type) を使用して、オブジェクトの型を定義します。
これらの方法の比較
- ユーティリティ型
インターフェースと同様の機能を提供しますが、より簡潔な構文を使用することができます。 - 型ガード
任意のオブジェクトに対してメソッドの存在をチェックすることができますが、コードが冗長になる可能性があります。 - インターフェース
抽象クラスよりも柔軟性があり、複数のクラスで同じインターフェースを実装することができます。
適切な方法を選択する際には、以下の点を考慮してください
- 任意のオブジェクトのチェック
任意のオブジェクトに対してメソッドの存在をチェックする場合は、型ガードまたはユーティリティ型を使用するのが適切です。 - 共通のインターフェース
複数のクラスで共通のインターフェースを定義する場合は、インターフェースを使用するのが適切です。 - クラスの階層関係
クラスが継承関係にある場合は、抽象クラスを使用するのが適切です。
typescript abstract-class abstract