web-dev-qa-db-ja.com

TypeScriptでの純粋な抽象クラスの拡張と実装

純粋な抽象クラス(つまり、実装のない抽象クラス)があるとします。

abstract class A {
    abstract m(): void;
}

C#やJavaのように、抽象クラスをextendできます:

class B extends A {
    m(): void { }
}

しかし、C#とJavaのunlikeと同様に、抽象クラスをimplementすることもできます。

class C implements A {
    m(): void { }
}

クラスBCはどのように振る舞いますか?なぜ一方を選択するのですか?

(現在、TypeScript ハンドブック および 言語仕様 は抽象クラスをカバーしていません。)

54
Michael Liu

implementsキーワードはAクラスをインターフェイスとして扱います。つまり、CはAで定義されたすべてのメソッドを実装する必要があります[〜#〜] a [〜#〜]に実装があるかどうかは関係ありません。また、[〜#〜] c [〜#〜]にはスーパーメソッドの呼び出しはありません。

extendsは、キーワードに期待するものと同じように動作します。抽象メソッドのみを実装する必要があり、スーパーコールは利用可能/生成されます。

抽象メソッドの場合、違いはないと思います。ただし、抽象メソッドのみのclassを使用することはめったにありません。そうする場合は、インターフェイス

これは、生成されたコードを見ると簡単にわかります。遊び場の例を作成しました here

69
toskv

私がここに導かれたのは、自分に同じ質問をしていましたが、答えを読んでいるときに、選択がinstanceof演算子にも影響するということでした。

抽象クラスはJSに発行される実際の値であるため、サブクラスがそれを拡張するときの実行時チェックに使用できます。

abstract class A {}

class B extends A {}

class C implements A {}

console.log(new B() instanceof A) // true
console.log(new C() instanceof A) // false
9
Tao

@ toskv's answer に基づいて、抽象クラスをextendにすると、super()を呼び出す必要がありますサブクラスのコンストラクター。抽象クラスをimplementする場合、super()を呼び出す必要はありません(ただし、で宣言されたすべてのメソッドを実装する必要があります)プライベートメソッドを含む抽象クラス)。

拡張する代わりに抽象クラスを実装すると、元のクラスの依存関係とコンストラクターを気にせずにテスト用の模擬クラスを作成する場合に便利です。

7
Cory

拡張の例では、実際にクラスに新しいものを追加することはありません。したがって、何も拡張されません。何も拡張しないことは有効なTypeScriptですが、この場合は「実装」の方が適切だと思われます。しかし、結局のところ、それらは同等です。

0
Quentin 2