Programmingバックエンド開発者

TypeScriptのクラスでメソッドのオーバーロードをどのように実装し、オーバーロードメソッドの記述時に避けるべきエラーは何ですか?また、型の考慮に関してどのような困難がある可能性がありますか?

Hintsage AIアシスタントで面接を突破

回答。

質問の背景:

TypeScriptは、他の厳格に型付けされた言語(例えばJavaやC#)と同様にメソッドのオーバーロードをサポートしていますが、TypeScriptにおけるオーバーロードの構文は概念的に異なります。ここでは、複数のシグネチャが許可されますが、実装は1つだけです。これは、従来のオーバーロードに慣れた開発者にとって混乱を招くことがあります。

問題:

一般的な誤りは、異なるパラメータセットを持つ複数のメソッドを定義しようとすることです。その結果、TypeScriptはすべてのシグネチャの実装を1つ要求するため、コンパイルエラーが発生します。

解決策:

オーバーロードは、メソッドのいくつかのシグネチャを宣言し、その後にすべてのバリエーションに対応する実装を行うことで達成されます。パラメータの正しい識別には、通常、type guardsやinstanceofを使用します。

コードの例:

class MyLogger { log(message: string): void; log(message: string, level: 'info' | 'error'): void; log(message: string, level?: 'info' | 'error'): void { const lvl = level ?? 'info'; console.log(`[${lvl}] ${message}`); } }

主な特徴:

  • メソッドは1つの実装を持っていますが、シグネチャは複数です
  • 実装内ですべての入力パラメータのバリエーションを処理する必要があります
  • 実装の型はできる限り広範であるべきです

トリッキーな質問。

異なるパラメータセットを持つ1つのメソッドの2つの実装を作成できますか?

いいえ。TypeScriptでは、1つの実装のみが許可されています。同じ名前の複数のメソッドは構文エラーです。

メソッドのオーバーロード時にrestパラメータをどのように型付けして厳格な型を失わないようにしますか?

シグネチャでは正確なパラメータを記述し、実装では可能な限り一般的なものを使用することが推奨されます:

class Test { doWork(a: number): void; doWork(a: string): void; doWork(a: number | string): void { //... } }

オーバーロードされたシグネチャの返り値の型が異なる場合、どうなりますか?

TypeScriptは、実装がユニオン型(Union)を返すことを要求します。そうでない場合、コンパイルエラーが発生します。

class X { get(value: number): string; get(value: string): number; get(value: number | string): string | number { return typeof value === 'number' ? 'number' : 42; } }

一般的なエラーとアンチパターン

  • オーバーロードのシグネチャと実装の不一致
  • 1つのメソッドの複数の個別の実装
  • メソッドの本体内での入力パラメータの型チェックの無視

実生活の例

ネガティブケース

製品内で異なる型のパラメータに対して同じ名前の2つのメソッドを実装しようとしました。コンパイル後、メソッドは最後の宣言によって「上書き」され、他のすべてのバージョンが無視され、バグが発生しました。

利点:

  • 一部の言語においてなじみのあるスタイル

欠点:

  • TypeScriptでは完全には機能せず、コンパイルエラーが発生
  • 経路の見落としのリスクが高い

ポジティブケース

ユニオン型パラメータを持ついくつかのシグネチャを作成し、メソッド内でtype guardsを通じてすべてのバリエーションを処理しました。コンパイラはすぐに型の問題について警告しました。

利点:

  • 厳格な型管理
  • 安全性
  • テストのしやすさ

欠点:

  • バリエーションのチェックにより多くのコードが必要