88
54

More than 1 year has passed since last update.

TypeScript: オーバーロードメソッドを定義する方法

Last updated at Posted at 2019-10-07

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))を書く必要がなくなる。

次に読むといいかもしれない

88
54
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
88
54