問題の歴史:JavaScriptでは、標準のエラーはErrorクラスで記述されています。大規模なTypeScriptプロジェクトでは、状況を正確に処理するために自分自身のエラー階層を使用することが重要ですが、型、継承、および'instanceof'の動作に関しては注意が必要です。
問題:Errorから継承する際に問題が発生する可能性があります。プロトタイプが失われ、'instanceof'が正しく機能せず、型が正確に記述されていない可能性があり、シリアル化はしばしばスタックトレースを失います。プロパティを明示的に指定しない場合、エラー処理でバグが発生する可能性があります。
解決策:Errorクラスを拡張してカスタムエラーを正しく定義します。名前を明示的に記述し、プロトタイプを手動で復元する必要があります(ES5やCommonJSへのコンパイル時に重要です)およびエラーフィールドの型を指定します。
コード例:
class ValidationError extends Error { code: number; constructor(message: string, code: number = 400) { super(message); Object.setPrototypeOf(this, ValidationError.prototype); this.name = 'ValidationError'; this.code = code; } } function process(user: string) { if (!user) throw new ValidationError('User required', 401); }
主な特徴:
Object.setPrototypeOf(this, ...)の呼び出しを省略できない理由は?
Object.setPrototypeOf(this, Class.prototype)を呼び出さなければならないのは、'instanceof' ValidationErrorがES5/CommonJSやBabelにコンパイルされた場合に機能しなくなるためです。これにより、catchブロックがValidationErrorをキャッチできなくなります。
class CustomErr extends Error {} const err = new CustomErr('msg'); console.log(err instanceof CustomErr); // setPrototypeOfなしではfalse
カスタムエラーのnameフィールドを省略しても良いか?
this.nameプロパティを設定しなければ、エラーのスタックとログ表示が不正確になり、原因とエラーの分類が難しくなります。
エラーをシリアライズ可能にする必要があるか?もしそうなら、どのように?
エラーは正しくシリアル化されるべきです(例:ロギングやネットワーク経由での送信のため)、さもなければJSON.stringify(new Error())はmessageやstackを出力しません。toJSONメソッドをオーバーライドする必要があります。
class SerializableError extends Error { toJSON() { return { name: this.name, message: this.message, stack: this.stack }; } }
プロジェクトでは、単にclass MyError extends Errorを行い、プロトタイプを復元せずにやっていました。エラーはif (err instanceof MyError)でキャッチされましたが、これは機能せず、コードはクリティカルな状況の処理をサイレントにスキップしました。
利点:
欠点:
正しいCustomErrorを実装し、name、code、toJSONを明示的に設定し、さまざまなタイプのエラー処理のテストをカバーしました。ログとcatchハンドラーではエラーの構造が明確になり、それによってバグの検索時間が短縮されました。
利点:
欠点: