typescriptを書いててC#やKotlinと同じ感覚でオーバーロードを書いたらエラーを吐かれたため
typescriptのオーバーロードの書き方をまとめました。
functionのオーバーロード
function test(a: string, b: string):number // 宣言
function test(a: number): number // 宣言
function test(a: number | string, b?: string): number { // 実装
if (typeof (a) === "string") {
return Number(a) + Number(b)
}
if(typeof(a) === "number"){
return a;
}
return 0
}
ご覧の通りtypescriptはオーバーロード時の関数の宣言だけをして、最後に全てのケースの型を受け取る前提の関数を定義して
実装します。
なので、引数として与えられないケースがある場合は optionalにする
1引数に複数の型が与えられる可能性がある場合は | で繋いでずべてのケースを書く必要があります。
constructorのオーバロード
クラスのコンストラクターのオーバーロードも同様です。
class Test {
#value1: number = 1;
#value2: number = 1;
constructor(value1:number)
constructor(value1?:number, value2?: number )
constructor(value1:number, value2:number)
constructor(value1?: number, value2?: number) {
if (value1 && value2) {
this.#value1 = value1;
this.#value2 = value2;
return;
}
if (value1) {
this.#value1 = value1;
return;
}
if (value2) {
this.#value2 = value2;
return;
}
}
get sum():number {
return this.#value1 + this.#value2;
}
}
const test1 = new Test(2);
const test2 = new Test(undefined, 3);
const test3 = new Test(4, undefined);
const test4 = new Test(3,3)
console.log(test1.sum) //3
console.log(test2.sum) //4
console.log(test3.sum) //5
console.log(test4.sum) //6
なおtsの仕様上
constructor(){}
のような意味のないコンストラクタを定義することはできないので、それを除いた形でオーバーロードします。
class method のオーバーロード
クラスメソッドも同様
class Test {
#value1: number = 1;
#value2: number = 1;
constructor(value1: number, value2: number) {
this.#value1 = value1;
this.#value2 = value2;
}
add():number
add(a:number):number
add(a?:number): number {
if(!a){
return this.#value1 + this.#value2;
}
return this.#value1 + this.#value2 + a;
}
}
さいごに
残念なことに、typescript は別のJavaなどと違って、オーバーロード解決(もらった引数の型などからオーバーロードされたパターンの内、一致制が高いものを自動的に算出する機構)をもっていないようなので、自前ですべてのパターンを実装する必要があります。
なので、むやみにオーバーロードすると、可読性や保守性を犠牲にしそうなので、注意しないといけないようです。