Edited at

TypeScriptで型の異なるメソッドをオーバーライドする

More than 3 years have passed since last update.


これはなに


  • TypeScriptでは親クラスのメソッドを継承する際、オーバーライド(同名メソッドの上書き)ができる

  • ただし、引数や返り値の型の異なる場合はオーバーライドできない

  • オーバーロード宣言と組み合わせる事で実現できる


前提:引数や返り値の型の異なるメソッドはオーバーライドできない

TypeScriptは(、元のES2015の仕様に合わせ)特に何の宣言も不要でメソッドのオーバーライドができる。ただしJSと異なるのは引数や返り値の型のチェックが入るため、一致しないとオーバーライドできない12


引数の型が異なるのでオーバーライドできない

class Base{

method(arg:string){}
}

//error! Type of property 'method' are incompatible.
class ChildA extends Base{
method(arg:number){}
}



対処法:オーバーロード宣言と組み合わせる

TypeScriptには同名メソッド・関数で引数・返り値の型や数などが異なる時用に、オーバーロードがある。

これをつかい、子クラス側で①継承元と同じ型のメソッドと②新しいメソッドをオーバーロードで宣言すればエラーにならず、継承できる。


class Base{
method(arg:string){}
}

//ok
class ChildB extends Base{
method(arg:number):void; //②
method(arg:string):void; //①
method(arg:any){
if(typeof arg === "string"){
super.method(arg);
}else if(typeof arg === "number"){
//...
}
}
}


親クラスと同じ型を拒否

親クラスと同じ型の引数だった場合を拒否するには、TSの型システムではできない。やるなら、以下のようにランタイムにチェックする。

class ChildB extends Base{

method(arg:number):void;
method(arg:string):void;
method(arg:any){
if(typeof arg === "string"){
throw TypeError(`Invalid type of argument. typeof arg: ${typeof arg}`);
}else if(typeof arg === "number"){
//...
}
}
}


参考:型定義

既存ライブラリ用に型定義ファイルを書くなら以下のようになる。


*.d.ts

declare class Base{

method(arg:string):void;
}

//ok
declare class ChildB extends Base{
method(arg:string):void;
method(arg:number):void;
}






  1. C++/Java/C#も同様。 



  2. なお、基底クラスのメソッドをprivateで宣言していてもダメ。