はじめに
interfaceとかextendsとか、よく分からない。。。。
疑問を持った経緯
ある日、引数にclassBの型をとる関数に遭遇しました。
function someFunction(param: classB) {
// classBの型を受け入れる関数
}
私
「引数にclassBの型が指定されているからclassBを使わないと」
先輩
「いや、違います。ここでは機能としてclassBをextendsしているclassAを使って実装します」
私
「え?なんでclassAも入れれるの??Bって書いてあるのに、、、」
先輩
「classAはclassBをextendsしているから使えるんですよ。」
「extendsがわからければ自分で調べて勉強してみてください。。。!」
が事の発端です。
本当にそうだった
先輩を疑っていたわけではないですが、
下記のコードのような場合、classAを入れてもclassBを入れても問題ないようです。
class classB {
// 何らかのプロパティやメソッド
}
export interface InterfaceA extends classB{
//インターフェースA独自のプロパティやメソッド
}
export class classA implements InterfaceA{
//クラスAの実装
}
classBの型を受け入れる関数に対して・・・
function someFunction(param: classB) {
// classBの型を受け入れる関数
}
classA,classBどちらをインスタンス化したやつを入れても正しくなった!
const instanceA = new classA();
someFunction(instanceA); // これは正しい
const instanceB = new classB();
someFunction(instanceB); // これも正しい
interfaceやextendsって何?
下記のコードの意味はこのような感じです
export interface InterfaceA extends classB
InterFaceAはclassBのインターフェースを継承し、外部で使えるものとして宣言
export
他のモジュールから(InterfaceA)を利用可能
interface InterfaceA
Aclassという新しいインタフェースの宣言
extends Bclass
Bclassのインターフェースを引き継ぐ
要するに
classBの interface (メソッドなどの設計要素)を extends (引き継いで)
作成したclassAは、classBの型を受け入れる関数で使えるようです。
しかし逆はエラーになるので注意です!
classAのインスタンスを受け入れる関数にclassBのインスタンスはNG!
まとめ
interface
classに作るメソッドを宣言することで、
実装漏れを防いだり、classが持つメソッドなどの設計図の役割をする
extends
別のモジュールのインターフェースをまるっと引き継ぐ
(追加する機能やメソッドの書き換えはinterface名を宣言した直後に書く)
まだまだ自分は修行が足りんですな。