TypeScriptのオーバーロードメソッドを定義する方法を説明する。
TypeScriptのオーバーロードは、Javaなどの他の言語から見ると特殊な定義の仕方になっている。
オーバーロードメソッドはインターフェイス部分と実装部分を別々に書く
TypeScriptのオーバーロードはJavaなどの言語とは異なり、メソッドのインターフェイス定義部分と、メソッドの実装部分を分けて書く。
// Kotlinのオーバーロードの例。
// よくある言語のオーバーロードは、インターフェイスと実装がひとまとまりになる書き方だが……
class Twicer {
fun twice(num: Int): Int {
return num * 2
}
fun twice(str: String): String {
return str + str
}
fun <T>twice(arr: Array<T>): Array<T> {
return arr + arr
}
}
// TypeScriptのオーバーロードの例。
// TypeScriptはインターフェイスと実装を分けて書く。
class Twicer {
// オーバーロードメソッドのインターフェイス
twice(num: number): number // 数を2倍する処理のインターフェイス
twice(str: string): string // 文字列を2回繰り返す処理のインターフェイス
twice<T>(arr: T[]): T[] // 配列要素を2倍にする処理のインターフェイス
// オーバーロードメソッドの実装
twice(value: any): any {
// 1つ目のオーバーロードメソッド twice(num: number): number の処理
if (typeof value === 'number') {
return value * 2
}
// 2つ目のオーバーロードメソッド twice(str: string): string の処理
if (typeof value === 'string') {
return value + value
}
// 3つ目のオーバーロードメソッド twice<T>(arr: T[]): T[] の処理
if (Array.isArray(value)) {
return [...value, ...value]
}
}
}
→このコードをTypeScript Playgroundで動かす
このTSコードをコンパイルしたJavaScriptコードは次のようになり、当然ながらオーバーロードメソッドのインターフェイス部分は消される:
// コンパイル後のJavaScriptコード
class Twicer {
twice(value) {
if (typeof value === 'number') {
return value * 2;
}
if (typeof value === 'string') {
return value + value;
}
return [...value, ...value];
}
}
オーバーロードメソッドの使い方はJavaなど他の言語と同様に、メソッド名は同じで引数の型だけ違う呼び出しができる:
const twicer = new Twicer()
const num: number = twicer.twice(1)
const str: string = twicer.twice('a')
const arr: string[] = twicer.twice(['item'])
console.log({ num, str, arr })
// Output:
// { num: 2, str: 'aa', arr: ['item', 'item'] }
もちろん、オーバーロードメソッドにないインターフェイスはコンパイルエラーになる:
twicer.twice(true) // 🚫boolを2倍するインターフェイスは無いのでコンパイルエラーになる
最初にあげたTypeScriptのオーバーロードメソッドの実装例では、引数の型と戻り値の型がany
になっていることに気がついたと思う。これは、number
, string
, T[]
をすべて扱えるようにするためだ。もちろんここにユニオン型を使うとany
を避けることができる。
class Twicer {
twice(num: number): number
twice(str: string): string
twice<T>(arr: T[]): T[]
twice<T>(value: number | string | T[]): number | string | T[] {
if (typeof value === 'number') {
return value * 2
}
if (typeof value === 'string') {
return value + value
}
return [...value, ...value]
}
}
→このコードをTypeScript Playgroundで動かす
この場合、1つ目のif分岐の次からはvalue: string | T[]
が推論され、2つ目のif分岐の次からはvalue: T[]
が推論されるため、3つ目のif(Array.isArray(value))
を書く必要がなくなる。
次に読むといいかもしれない