TypeScriptで同じ関数名で異なる引数パターンを型安全に受け付ける方法。
基本構造
// 1. オーバーロードシグネチャ(宣言のみ)
export function myFunction(arg1: Type1): ReturnType1;
export function myFunction(arg1: Type2, arg2: Type3): ReturnType2;
// 2. 実装シグネチャ(実際の実装)
export function myFunction(
arg1: Type1 | Type2,
arg2?: Type3,
): ReturnType1 | ReturnType2 {
// 実装
}
実装例
// パターン1: 配列を受け取る
export function process(items: string[]): void;
// パターン2: 個別の値を受け取る
export function process(value: string, index: number): void;
// 実装シグネチャ
export function process(
valueOrItems: string | string[],
index?: number,
): void {
if (Array.isArray(valueOrItems)) {
// 配列の処理
valueOrItems.forEach((item, i) => console.log(item, i));
} else {
// 単一値の処理
if (index === undefined) {
throw new Error('index is required for single value');
}
console.log(valueOrItems, index);
}
}
// 使用例
process(['a', 'b', 'c']); // ✅ OK
process('hello', 0); // ✅ OK
process('hello'); // ❌ コンパイルエラー
重要なポイント
- シグネチャの順序: より具体的なパターンを先に記述する
- 実装シグネチャは非公開: 呼び出し側からはオーバーロードシグネチャのみが見える
- 実装は全パターンに対応: Union型やオプショナル引数で全パターンを受け入れる
- 型安全性: コンパイル時に不正な呼び出しを検出できる
- 実行時チェック: オプショナル引数を使った場合は、実行時にundefinedチェックを行う
複数パターンの例
export function format(value: string): string;
export function format(value: number): string;
export function format(value: Date): string;
export function format(value: string | number | Date): string {
if (typeof value === 'string') return value;
if (typeof value === 'number') return value.toString();
return value.toISOString();
}
メリット
- 異なる使用パターンを1つの関数で提供
- 型チェックによる安全性
- APIの柔軟性向上
- コードの重複を避けられる