5.3 クラスの継承
継承とは、あるクラス(親クラス)に機能を追加・拡張した別のクラス(子クラス)を作成する機能です。子クラスのインスタンスは親クラスのインスタンスの代わりに使用できる(部分型になる)という特徴があります。
5.3.1 継承(1)子は親の機能を受け継ぐ
Section titled “5.3.1 継承(1)子は親の機能を受け継ぐ”extends キーワードを使用することで、親クラスの機能を受け継ぐ子クラスを宣言できます。
- 構文:
class 子クラス名 extends 親クラス名 { ... } - 機能の継承: 子クラスは、親クラスが持つすべてのプロパティ、メソッド、コンストラクタを自動的に引き継ぎます。これに加えて、子クラス独自のプロパティやメソッドを追加できます。
5.3.2 継承(2) 親の機能を上書きする
Section titled “5.3.2 継承(2) 親の機能を上書きする”子クラスでは、親クラスが持つ機能を再宣言することで、その挙動を上書き(オーバーライド)することができます。
- 型の制約: オーバーライドするメソッドは、親クラスのメソッドの型と合致(または部分型に)している必要があります。
- コンストラクタの上書き: 子クラスでコンストラクタを再定義する場合は、必ず内部で
super()を呼び出し、親クラスのコンストラクタを実行する必要があります。また、super()はthisにアクセスするよりも前に呼び出さなければなりません。
5.3.3 override修飾子とその威力
Section titled “5.3.3 override修飾子とその威力”オーバーライドを行う際、プロパティやメソッドに override 修飾子を付けることができます。
- 効果: 親クラスに存在しないものをオーバーライドしようとした場合(タイポや親クラスの仕様変更時など)に、コンパイルエラーとして検知してくれます。
- 安全性の向上:
tsconfig.jsonでnoImplicitOverrideオプションを有効にすると、オーバーライド時にoverride修飾子が必須となり、意図しないバグを未然に防ぐことができます。
5.3.4 private protectedの動作と使いどころ
Section titled “5.3.4 private protectedの動作と使いどころ”継承時におけるアクセス修飾子の使い分けは重要です。
protected: クラス外部からはアクセスできませんが、子クラスからはアクセス可能です。- 設計の注意点:
protectedを安易に使うと、子クラスが親クラスの内部状態を勝手に書き換えてバグを引き起こすリスクがあります。安全なプログラムを書くためには、極力privateや#を用いてカプセル化を保つべきです。
コラム23 継承で明らかになるprivateと#の差異
Section titled “コラム23 継承で明らかになるprivateと#の差異”親クラスと子クラスで同じ名前のプライベートプロパティを定義した場合の挙動が異なります。
private: 親と子で同じプロパティ名を使うとコンパイルエラーになります。#: クラスごとに独立した名前空間で管理されるため、親と子で同じ#プロパティ名を定義しても衝突せず、別々のプロパティとして扱われます[cite: 1]。継承を多用する場合は#の方が便利です[cite: 1]。
5.3.5 implementsキーワードによるクラスの型チェック
Section titled “5.3.5 implementsキーワードによるクラスの型チェック”implements キーワードは、そのクラスが指定した「型」の要件を満たしている(部分型である)ことを宣言・保証するためのものです[cite: 1]。
- 構文:
class クラス名 implements 型名 { ... }[cite: 1](継承と併用する場合はextendsの後に書きます[cite: 1])。 - メリット: TypeScriptは構造的部分型のため
implementsを書かなくても型の互換性は満たせますが、明記することで「クラス宣言の時点」で要件漏れ(プロパティの欠如など)をコンパイルエラーとして早期発見できます[cite: 1]。