関数オーバーロードは、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つのみで、すべてのオーバーロードをカバーする必要あり
- 実装の型は
any
や unknown
にしがち → 型安全が崩れないように制御を明示する
- 引数の数や型を変えたいだけの場合は デフォルト引数や オプショナル引数でも代替可能
✅ まとめ
特徴 |
内容 |
関数オーバーロード |
複数の呼び出しシグネチャを定義できる |
実装は1つのみ |
すべてのシグネチャを包含する必要がある |
呼び出し時に推論 |
IDEや型システムが適切な型を選択してくれる |
ユースケース |
API関数/ユーティリティ関数/異なる返り値の型に対応したい時など |
📚 オーバーロードが活躍する場面
- 型によって異なる処理を行う共通関数(例:文字列or配列)
- 第1引数と第2引数の組み合わせで返り値が変わる関数
- 同じ関数名で型ごとに異なる返却値を保証したい場面