関数オーバーロード 同一関数名で型違いの制御

関数オーバーロードは、1つの関数で複数の呼び出しパターンを定義する仕組みです。
JavaScriptでは実現できなかった、関数ごとの型安全なAPI設計が可能になります。


✅ 基本構文

function func(x: number): number;
function func(x: string): string;
function func(x: number | string): number | string {
  return x;
}

🔍 ポイント

  • 上の2つが「オーバーロードシグネチャ」
  • 最後の1つが「実装(implementation)」で、引数の型を包含する必要がある
  • TypeScriptは呼び出し時に合致するオーバーロードを自動的に推論する

🧩 実例:文字列か数値を渡せる関数

function toArray(value: number): number[];
function toArray(value: string): string[];
function toArray(value: number | string): (number | string)[] {
  return [value];
}

toArray(123);      // 推論: number[]
toArray("hello");  // 推論: string[]

📦 実用例:日時のフォーマット関数

function formatDate(date: string): string;
function formatDate(date: Date): string;
function formatDate(date: string | Date): string {
  const d = typeof date === "string" ? new Date(date) : date;
  return d.toISOString().split("T")[0];
}

formatDate("2023-01-01"); // OK
formatDate(new Date());   // OK

🔍 オーバーロード vs ユニオン型の違い

ユニオン型を使う 関数内部で型チェックが必要
オーバーロード 呼び出しごとに異なる返り値の型を保証できる
// ユニオン型のみ
function double(value: number | string) {
  return typeof value === "number" ? value * 2 : value + value;
}
// オーバーロードで型別に分ける
function double(value: number): number;
function double(value: string): string;
function double(value: number | string): number | string {
  return typeof value === "number" ? value * 2 : value + value;
}

⚠️ 注意点

  • 実装は1つのみで、すべてのオーバーロードをカバーする必要あり
  • 実装の型は anyunknown にしがち → 型安全が崩れないように制御を明示する
  • 引数の数や型を変えたいだけの場合は デフォルト引数オプショナル引数でも代替可能

✅ まとめ

特徴 内容
関数オーバーロード 複数の呼び出しシグネチャを定義できる
実装は1つのみ すべてのシグネチャを包含する必要がある
呼び出し時に推論 IDEや型システムが適切な型を選択してくれる
ユースケース API関数/ユーティリティ関数/異なる返り値の型に対応したい時など

📚 オーバーロードが活躍する場面

  • 型によって異なる処理を行う共通関数(例:文字列or配列)
  • 第1引数と第2引数の組み合わせで返り値が変わる関数
  • 同じ関数名で型ごとに異なる返却値を保証したい場面
コメントを残す 0

Your email address will not be published. Required fields are marked *