TypeScript
オーバーライド
オーバーロード

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

More than 1 year has 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で宣言していてもダメ。