メインコンテンツまでスキップ

オーバーロード関数 (overload functions)

オーバーロードとは、関数の名称は同じでありながら異なる引数、戻り値を持つことができる機能です。TypeScriptもこの機能を用意しているのですが、大元がJavaScriptであることが災いし、やや使いづらいです。

オーバーロードの定義#

オーバーロードはその関数が受け付けたい引数、戻り値の組を実装する関数の上に書きます。先ほど使用した2点の距離を求める関数distance()をオーバーロードで定義すると次のようになります。なお、この例では戻り値の型はすべてnumber型ですが、別の型にしても実装さえできれば他の型にしても問題ありません。

typescript
function distance(p: Point): number;
function distance(p1: Point, p2: Point): number;
function distance(x: number, y: number): number;
function distance(x1: number, y1: numebr, x2: number, y2: number): number;
typescript
function distance(p: Point): number;
function distance(p1: Point, p2: Point): number;
function distance(x: number, y: number): number;
function distance(x1: number, y1: numebr, x2: number, y2: number): number;

なお、上記のような書き方のオーバーロードは名前付き関数またはクラスのメソッドでのみ可能です。匿名関数、アロー関数ではタイプエイリアスまたはインターフェースでオーバーロードを定義します。たとえば、上記例だと次のようなタイプエイリアスになります。

typescript
type Distance = {
(p: Point): number;
(p1: Point, p2: Point): number;
(x: number, y: number): number;
(x1: number, y1: number, x2: number, y2: number): number;
};
const distance: Distance = (
arg1: number | Point,
arg2?: number | Point,
arg3?: number,
arg4?: number
): number => {
// ...
};
typescript
type Distance = {
(p: Point): number;
(p1: Point, p2: Point): number;
(x: number, y: number): number;
(x1: number, y1: number, x2: number, y2: number): number;
};
const distance: Distance = (
arg1: number | Point,
arg2?: number | Point,
arg3?: number,
arg4?: number
): number => {
// ...
};

オーバーロードの実装#

ここからが大変です。実装はオーバーロードで定義したすべてをひとつの関数で処理しなければいけません。つまりdistance()の実装は次のようになります。これが呼び出し側ではあたかも他言語のオーバーロードのようになります。

typescript
function distance(p: Point): number;
function distance(p1: Point, p2: Point): number;
function distance(x: number, y: number): number;
function distance(x1: number, y1: numebr, x2: number, y2: number): number;
function distance(
arg1: Point | number,
arg2?: Point | number,
arg3?: number,
arg4?: number
): number {
// ...
}
distance(q1);
distance(q1, q2);
distance(1, 3);
distance(1, 3, 5, 7);
typescript
function distance(p: Point): number;
function distance(p1: Point, p2: Point): number;
function distance(x: number, y: number): number;
function distance(x1: number, y1: numebr, x2: number, y2: number): number;
function distance(
arg1: Point | number,
arg2?: Point | number,
arg3?: number,
arg4?: number
): number {
// ...
}
distance(q1);
distance(q1, q2);
distance(1, 3);
distance(1, 3, 5, 7);

オーバーロードでうれしいこと#

オーバーロードの定義なしに実装すると次のような引数を考慮しなければなりません。

typescript
distance(q1, 5, undefined, 8);
typescript
distance(q1, 5, undefined, 8);

オーバーロードを定義しておくことで意図する引数と戻り値の組み合わせを定義できるようになります。上記引数はオーバーロードの定義によりTypeScriptから指摘を受けます。

typescript
Argument of type 'Point' is not assignable to parameter of type 'number'.
typescript
Argument of type 'Point' is not assignable to parameter of type 'number'.

これはTypeScriptがdistance()number型の引数4個版で受けていると解釈している時の指摘です。