Skip to content

TypeScript 関数オーバーロード

addNumbers関数の実装

ts
function addNumbers(a: number | string, b: number | string) {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b
  } else {
    return a.toString() + b.toString()
  }
}

const result = addNumbers("1", "2")

result.includes('1')
// プロパティ 'includes' は型 'string | number' に存在しません。
// プロパティ 'includes' は型 'number' に存在しません。

 上記の例の、addNumbers関数では、パラメータabの型、そして戻り値の方はすべてnumber | stringというユニオン型。関数内では、typeof演算子を用いたif文で引数の型をチェックし、量引数が数値の場合には加算をお粉、それ以外の場合には文字列として結合する処理をしている。

 しかし、このアプローチには問題がある。関数に文字列を渡したときに戻り値に対してstring型のメソッドを使用しようとすると、TypeScriptはエラーを発生させる。その理由は、TypeScriptaddNumbers関数の戻り値をnumber | stringと推論しており、戻り値がnumberの可能性もあるため、string型専用のメソッドを安全に呼び出すことができないと判断するから。

 この問題を解決するために、TypeScriptでは関数オーバーロードを使用する。関数オーバーロードを用いると、同じ名前の関数に対して複数の呼び出しシグネチャを定義可能。これにより、関数の呼び出し方法に応じて、TypeScriptコンパイラによる型推論をより正確に行わせることが可能。

関数オーバーロード

ts
// オーバーロードのシグネチャ
function addNumbers(a: number, b: number): number
function addNumbers(a: string, b: string): string
function addNumbers(a: number, b: string): string
function addNumbers(a: string, b: number): string

function addNumbers(a: number | string, b: number | string): number | string {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b
  } else {
    return a.toString() + b.toString()
  }
}

const result = addNumbers('1', '2') // result は string 型として推論される
// string 型と推論されているためエラーにならない
result.includes('1') // true