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

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

序文:

ほとんどの関数は固定されたパラメータセットを受け入れます。ただし、一部の関数では、関数の呼び出し方法に応じて、可変数の引数、異なる型の引数を受け入れたり、異なる型を返したりすることもできます。このような関数に注釈を付けるために、TypeScript は関数オーバーロードを提供します。

1. 関数シグネチャ

まず、特定の人に挨拶メッセージを返す関数を考えてみましょう。

関数greet(人: 文字列): 文字列 {
  `Hello, ${person}!` を返します。
}


上記の関数は、文字型の引数 1 つ (人の名前) を受け入れます。関数の呼び出しは非常に簡単です:

greeting('World'); // 'こんにちは、World!'


greet()関数をより柔軟にしたい場合はどうすればよいでしょうか?たとえば、挨拶する人のリストを追加で受け入れるようにします。

このような関数は、文字列または文字列の配列を引数として受け入れ、文字列または文字列の配列を返します。

このような関数に注釈を付けるにはどうすればよいでしょうか?方法は2つあります。

最初のアプローチは簡単で、パラメータと戻り値の型を更新して関数シグネチャを直接変更します。

リファクタリング後のgreet()は次のようになります。

関数greet(person: 文字列 | 文字列[]): 文字列 | 文字列[] {
  if (typeof person === 'string') {
    `Hello, ${person}!` を返します。
  } そうでない場合 (Array.isArray(person)) {
    person.map(name => `こんにちは、${name}!`) を返します。
  }
  新しいエラーをスローします('挨拶できません');
}


これで、greet() を 2 つの方法で呼び出すことができます。

greeting('World'); // 'こんにちは、World!'
greeting(['Xiaozhi', 'Daye']); // ['こんにちは、Xiaozhi!', 'こんにちは、Daye!']


複数の呼び出しメソッドをサポートするために関数シグネチャを直接更新することは、一般的で適切なアプローチです。

ただし、場合によっては、別のアプローチを採用し、関数を呼び出すすべての方法を個別に定義する必要があります。このアプローチは関数オーバーロードと呼ばれます。

2. 関数のオーバーロード

2 番目の方法は、関数オーバーロードを使用することです。関数シグネチャが比較的複雑で、複数の型が関係する場合は、このアプローチをお勧めします。

関数オーバーロードを定義するには、オーバーロード シグネチャと実装シグネチャを定義する必要があります。

オーバーロードされたシグネチャは、関数本体なしで、関数のパラメーターと戻り値の型を定義します。関数には、関数を呼び出すさまざまな方法に対応する複数のオーバーロードされたシグネチャを含めることができます。

一方、実装シグネチャには、実装関数の本体だけでなく、パラメータの型と戻り値の型もあり、実装シグネチャは 1 つしか存在できません。

// オーバーロードシグネチャ function greeting(person: string): string;
関数greet(persons: string[]): string[];
 
// シグネチャ関数を実装するgreet(person: unknown): unknown {
  if (typeof person === 'string') {
    `Hello, ${person}!` を返します。
  } そうでない場合 (Array.isArray(person)) {
    person.map(name => `こんにちは、${name}!`) を返します。
  }
  新しいエラーをスローします('挨拶できません');
}


greet()関数には、2 つのオーバーロード シグネチャと 1 つの実装シグネチャがあります。

各オーバーロード シグネチャは、関数を呼び出す 1 つの方法を記述します。 greet()関数に関しては、文字列引数を使用するか、文字列の配列を使用するかの 2 つの方法で呼び出すことができます。

実装シグネチャfunction greet(person: unknown): unknown { ... }は、この関数がどのように動作するかに関する適切なロジックが含まれています。

これで、上記のように、 greet()文字列または文字列の配列で呼び出すことができます。

greeting('World'); // 'こんにちは、World!'
greeting(['Xiaozhi', 'Daye']); // ['こんにちは、Xiaozhi!', 'こんにちは、Daye!']


2.1 オーバーロードされたシグネチャは呼び出し可能

実装シグネチャは関数の動作を実装しますが、直接呼び出すことはできません。オーバーロードされたシグネチャのみが呼び出し可能です。

greeting('World'); // オーバーロードされたシグネチャ呼び出し可能関数 greeting(['Xiaozhi', 'Daye']); // オーバーロードされたシグネチャ呼び出し可能関数 const someValue: unknown = 'Unknown';
greeting(someValue); // 実装シグネチャは呼び出し可能ではない

// エラーを報告します。この呼び出しに一致するオーバーロードはありません。
  オーバーロード 1/2、「(person: string): string」で次のエラーが発生しました。
    'unknown' 型の引数は 'string' 型のパラメータに割り当てることができません。
  オーバーロード 2/2、「(persons: string[]): string[]」で次のエラーが発生しました。
    'unknown' 型の引数は 'string[]' 型のパラメータに割り当てることができません。

上記の例では、実装シグネチャがunknown引数を受け入れる場合でもunknown (greet(someValue))を使用してgreet()関数を呼び出すことはできません。

2.1 実装署名は普遍的でなければならない

// オーバーロードシグネチャ function greeting(person: string): string;
関数greet(persons: string[]): string[]; 
// このオーバーロード シグネチャは、実装シグネチャと互換性がありません。

 
// シグネチャ関数を実装するgreet(person: unknown): string {
  // ...
  新しいエラーをスローします('挨拶できません');
}

オーバーロードされたシグネチャ関数greet(person: string[]): string[] greet(person: unknown): stringと互換性がないとしてマークされています。

実装シグネチャのstring戻り型は、オーバーロードされたシグネチャのstring[]戻り型と互換性があるほど汎用的ではありません。

3. メソッドのオーバーロード

前の例では、関数オーバーロードが通常の関数に適用されました。しかし、メソッドをオーバーロードすることもできます

メソッド オーバーロード セクションでは、オーバーロード シグネチャと実装シグネチャの両方がクラスの一部になります。

たとえば、オーバーロードされたメソッドgreet()を持つGreeterクラスを実装します。

クラス Greeter {
  メッセージ: 文字列;
 
  コンストラクター(メッセージ: 文字列) {
    this.message = メッセージ;
  }
 
  // オーバーロードシグネチャ greeting(person: string): string;
  挨拶(人物: 文字列[]): 文字列[];
 
  // シグネチャを実装するgreet(person: unknown): unknown {
    if (typeof person === 'string') {
      `${this.message}, ${person}!` を返します。
    } そうでない場合 (Array.isArray(person)) {
      person.map(name => `${this.message}, ${name}!`) を返します。
    }
    新しいエラーをスローします('挨拶できません');
  }

Greeterクラスには、greet()オーバーロードメソッドが含まれています。メソッドの呼び出し方法を記述する2つのオーバーロードシグネチャと、正しい実装を含む実装シグネチャです。

メソッドのオーバーロードのおかげで、hi.greet() を、文字列または文字列の配列を引数として 2 つの方法で呼び出すことができます

const hi = new Greeter('Hi');
 
hi.greet('Xiaozhi'); // 'こんにちは、Xiaozhi!'
hi.greet(['Wang Daye', 'Daye']); // ['こんにちは、Wang Daye!', 'こんにちは、Daye!']


4. 関数オーバーロードを使用する場合

関数オーバーロードを適切に使用すると、複数の方法で呼び出される可能性のある関数の使いやすさが大幅に向上します。これは、自動補完を行うときに特に便利です。自動補完では、可能なすべてのオーバーロードがリストされます。

ただし、場合によっては、関数オーバーロードではなく、関数シグネチャを使用することをお勧めします。

たとえば、オプションのパラメータを持つ関数のオーバーロードは使用しないでください。

// 推奨されません function myFunc(): string;
関数 myFunc(param1: 文字列): 文字列;
関数 myFunc(param1: 文字列、param2: 文字列): 文字列;
関数 myFunc(...args: 文字列[]): 文字列 {
  // 実装...
}


関数シグネチャでオプションのパラメータを使用するだけで十分です。

// 推奨される方法 function myFunc(param1?: string, param2: string): string {
  // 実装...
}

5. まとめ

TypeScriptの関数オーバーロードを使用すると、複数の方法で呼び出すことができる関数を定義できます。

関数オーバーロードを使用するには、オーバーロード シグネチャ (パラメーターと戻り値の型を持ち、本体を持たない関数のセット) を定義する必要があります。これらのシグネチャは、関数をどのように呼び出すかを示します。

さらに、関数の正しい実装 (実装シグネチャ)、つまりパラメータと戻り値の型、および関数本体** を記述する必要があります。実装シグネチャは呼び出し可能ではないことに注意してください。 **

通常の関数に加えて、クラス内のメソッドもオーバーロードできます。

TypeScriptの関数オーバーロードに関するこの記事はこれで終わりです。TypeScript の関数オーバーロードの詳細については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • TypeScript における型とインターフェースの違いの詳細な説明
  • Typescript で for...in を使用する方法
  • TypeScript および JavaScript プロジェクトに MD5 チェックサムを導入する
  • TypeScript コア基盤インターフェース
  • TypeScriptは関数のオーバーロードを宣言するためにタプルユニオンを使用する

<<:  Dockerのプロセスとイメージを実行するための基本コマンドの詳細な説明

>>:  jQuery エディタ プラグイン tinyMCE の使い方

推薦する

MySQL Community Server 圧縮パッケージのインストールと設定方法

今日は、MySQL をインストールしたかったので、公式 Web サイトにアクセスして、MySQL の...

win10にmysql 8.0.18-winx64をインストールする詳細な手順

1. まず公式ウェブサイトにアクセスしてMySQLインストールパッケージをダウンロードします参考: ...

MySQL5.7.27-winx64 バージョン win10 のダウンロードとインストールのチュートリアル図

MySQL 5.7 のインストール私たちは学校で MySQL データベースを学んでいます。先生は私た...

ノードにおけるhttpモジュールの使用と実行プロセス

ノードにおけるhttpの役割は何ですか? httpモジュールの役割は、サーバーの作成と記述を支援する...

MySQL の分離レベル、ロック、MVCC の紹介

この記事の目的は、これらの概念とその機能の関係を明らかにすることです。 Mysql がトランザクショ...

MySQL MVCCメカニズム原理の詳細な説明

目次MVCCとはMySQL ロックとトランザクション分離レベルMySQL 元に戻すログMVCCの実装...

CentOS 6.5 の設定 ssh キーフリーログインで pssh コマンドを実行する方法の説明

1. psshを確認してインストールします。yum list pssh 2. キーレスログインが設定...

MySQL MGR の利点は何ですか?

MGR (MySQL グループ レプリケーション) は、バージョン 5.7 で追加された新しい機能...

フレックスレイアウトが子要素によって引き伸ばされたときに、コンテンツをコンテナ内に保持する方法

モバイル デバイスでは、フレックス レイアウトが非常に便利です。デバイスの幅に応じてコンテナーの幅を...

HTTP および HTTP コラボレーション Web サーバー アクセス フロー図

Web サーバーは、独立したドメイン名を持つ複数の Web サイトを構築できるほか、通信経路上のトラ...

Gitlab実践チュートリアルでは、関連する設定操作にgit configを使用します。

この記事では、実際に発生した問題をもとに、git の設定に関する内容を紹介します。コマンド: git...

JavaScriptのスリープ関数の使用

目次1.スリープ機能2.タイムアウトを設定する3. 約束4. 非同期待機5. 1秒後に出力1、2秒後...

MySQLループは数千万のデータを挿入する

1. テストテーブルを作成する テーブル `mysql_genarate` を作成します ( `id...

WebプロジェクトのDockerデプロイメントの実装

前回の記事では、docker サービスをインストールしました。引き続き、Web プロジェクトのデプロ...

Vue+nodeはオーディオ録音・再生機能を実現

結果: コードロジックを実装するのが主な部分であり、具体的なページ構造を一つ一つ紹介することはありま...