JavaScript >> Javascript チュートリアル >  >> Tags >> TypeScript

TypeScript での関数のオーバーロード

いくつかの JavaScript ライブラリが reverse を定義していると仮定しましょう 文字列と配列の両方で機能する関数。いずれの場合も、元の値を変更することなく、入力の逆バージョンを返します:

function reverse(stringOrArray) {
  return typeof stringOrArray === "string"
    ? stringOrArray.split("").reverse().join("")
    : stringOrArray.slice().reverse();
}

これは説明目的でのみ使用される単純な実装であることに注意してください。適切な実装では、2 つ以上のコード単位を使用して表される Unicode コード ポイントを処理する必要があります。さらに入力の検証も行います。さらに良いアイデアは、関数を 2 つの別個のものに分割することです。

とはいえ、reverse はどのように入力すればよいでしょうか TypeScript の関数?

#バージョン #1:任意のタイプ

最も簡単な方法は、パラメーターと戻り値の両方に any で注釈を付けることです。 JavaScript の任意の値が有効な型:

function reverse(stringOrArray: any): any {
  // ...
}

もちろん、このアプローチでは、TypeScript コンパイラはあまり役に立ちません。パラメーターの型に制限を課していないため、コンパイラーは実行時エラーがスローされるパラメーターを問題なく受け入れます。

reverse(true);
reverse({});
reverse(Math.random);

このような間違いを避けるために、もっと具体的にする必要があります。

#バージョン #2:ユニオン型

より洗練された型への次のステップとして、ユニオン型を使用して stringOrArray パラメータは、任意の型の文字列または要素の配列のいずれかでなければなりません。結果の共用体タイプは string | any[] です 、これをパラメーターと戻り値の両方の型として使用します:

function reverse(stringOrArray: string | any[]): string | any[] {
  // ...
}

これらの型注釈を配置すると、前の例の不適切な呼び出しは型エラーになりますが、正しい呼び出しは許可されます:

reverse(true); // Error!
reverse({}); // Error!
reverse(Math.random); // Error!

const elpmaxe: string | any[] = reverse("example");
const numbers: string | any[] = reverse([1, 2, 3, 4, 5]);

残念ながら、いくつかの型情報が失われました。 numbers の型 定数は、型 number[] の引数を渡したことが反映されていません reverse に 関数。共用体型の 2 番目の構成型が number[] であると、より便利です。 、 any[] ではありません .

#バージョン #3:ユニオン型 + ジェネリック

reverse を入力する少し良い方法 関数は、ジェネリック型を使用することです。配列要素を any と入力する代わりに 、一般的に T と入力できます .そうすれば、stringOrArray パラメータは string 型のいずれかです またはタイプ T[] .同じことが戻り値にも当てはまります:

function reverse<T>(stringOrArray: string | T[]): string | T[] {
  // ...
}

これで、型情報が保持されます:

const elpmaxe: string | string[] = reverse("example");
const numbers: string | number[] = reverse([1, 2, 3, 4, 5]);

率直に言って、関数型はまだ最適ではありません。戻り値の共用体型のため、map などの配列プロトタイプ メソッドにアクセスできません。 、配列を渡すと配列が返されることはわかっていますが。一方、型システムにはそのような知識がありません。可能なパラメーターと戻り型の組み合わせをまだ正確にモデル化していないためです。

その署名によると、reverse 関数は文字列または配列を受け取り、文字列または配列を返します。別の言い方をすれば、この関数には、次の 4 つのパラメーターと戻り値の型の組み合わせがあります。

  • (stringOrArray: string) => string
  • (stringOrArray: string) => T[]
  • (stringOrArray: T[]) => string
  • (stringOrArray: T[]) => T[]

しかし、それは reverse の方法ではありません 関数が動作します。関数の実装を考えると、次の 2 つの組み合わせのみが実行時に発生します:

  • (stringOrArray: string) => string
  • (stringOrArray: T[]) => T[]

その知識を型システムに反映する方法を見てみましょう。

#バージョン #4:関数のオーバーロード

他のプログラミング言語では、reverse をオーバーロードできます。 関数は、同じ名前で異なるタイプの 2 つの関数を記述します:

function reverse(string: string): string {
  return string.split("").reverse().join("");
}

function reverse<T>(array: T[]): T[] {
  return array.slice().reverse();
}

ただし、これは有効な TypeScript ではありません。同じスコープに同じ名前の 2 つの関数を含めることはできないためです。考えてみてください:上記のコードはどのように JavaScript にトランスパイルされますか? reverse が 2 つになってしまいます 名前で区別できない関数。

代わりに、TypeScript ではオーバーロード リストを指定して、同じ関数に複数の型を提供できます。そうすれば、型システムに対して、関数が何を受け入れ、何を返すかを正確に記述できます。

function reverse(string: string): string;
function reverse<T>(array: T[]): T[];
function reverse<T>(stringOrArray: string | T[]): string | T[] {
  return typeof stringOrArray === "string"
    ? stringOrArray.split("").reverse().join("")
    : stringOrArray.slice().reverse();
}

上記の例の最初の 2 行には、reverse の有効なオーバーロードがリストされています。 関数。必要に応じて、関数の「外部」シグネチャを表します。 3 行目では、指定されたすべてのオーバーロードと互換性がなければならない汎用の「内部」シグネチャを指定します。これらのオーバーロードが IDE (この場合は Visual Studio) でどのように表示されるかを次に示します。

最初の 2 つのオーバーロードのみがオートコンプリート リストに表示されることに注意してください。共用体型を使用して型付けされた実装自体は表示されません。また、型に応じて、より適切なパラメーター名を指定できるようになったことにも注目してください。以上です!関数のオーバーロードを使用して、reverse を正確に入力することができました 関数。


  1. カスタム バベル変換を作成するためのステップバイステップ ガイド

  2. 知っておくべき ES2020 の 10 の新しい JavaScript 機能

  3. 猫とAPI