カスタムエラークラスを作る|JavaScript
組み込みのエラー型(TypeError、RangeError など)だけでは、アプリケーション固有のエラーを表現しきれないことがあります。そんなときはカスタムエラークラスを作成して、より意味のあるエラーハンドリングを実現しましょう。
基本的なカスタムエラー
Error クラスを継承して独自のエラークラスを作ります。
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
throw new ValidationError('入力値が不正です');super(message) で親クラスの Error を初期化し、this.name でエラー名を設定します。
なぜ this.name を設定するのか
this.name を設定しないと、エラー名が親クラスの “Error” のままになってしまいます。
name を設定しない場合
Error: 入力値が不正です
name を設定した場合
ValidationError: 入力値が不正です
デバッグ時にエラーの種類がひと目でわかるようになります。
追加のプロパティを持たせる
カスタムエラーには独自のプロパティを追加できます。
class HttpError extends Error {
constructor(statusCode, message) {
super(message);
this.name = 'HttpError';
this.statusCode = statusCode;
}
}
try {
throw new HttpError(404, 'ページが見つかりません');
} catch (error) {
console.log(error.name); // "HttpError"
console.log(error.statusCode); // 404
console.log(error.message); // "ページが見つかりません"
}API のエラーレスポンスを扱う際などに便利です。
実用的なカスタムエラーの例
アプリケーションでよく使われるカスタムエラーの例を見てみましょう。
// 認証エラー
class AuthenticationError extends Error {
constructor(message = '認証に失敗しました') {
super(message);
this.name = 'AuthenticationError';
}
}
// 権限エラー
class AuthorizationError extends Error {
constructor(message = 'この操作を行う権限がありません') {
super(message);
this.name = 'AuthorizationError';
}
}
// バリデーションエラー(フィールド情報付き)
class FieldValidationError extends Error {
constructor(field, message) {
super(message);
this.name = 'FieldValidationError';
this.field = field;
}
}カスタムエラーを使った分岐処理
instanceof でカスタムエラーの種類を判定し、適切な処理を行えます。
async function fetchUser(id) {
try {
const response = await api.getUser(id);
return response;
} catch (error) {
if (error instanceof AuthenticationError) {
redirectToLogin();
} else if (error instanceof AuthorizationError) {
showPermissionDenied();
} else if (error instanceof HttpError && error.statusCode === 404) {
showUserNotFound();
} else {
showGenericError(error);
}
}
}エラー階層を作る
カスタムエラー同士で継承関係を作ることも可能です。
class AppError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
}
}
class NetworkError extends AppError {}
class TimeoutError extends NetworkError {}
class ConnectionError extends NetworkError {}this.constructor.name を使うと、継承先でも自動的に正しいクラス名が name にセットされます。
const timeout = new TimeoutError('接続がタイムアウトしました');
console.log(timeout instanceof TimeoutError); // true
console.log(timeout instanceof NetworkError); // true
console.log(timeout instanceof AppError); // true
console.log(timeout instanceof Error); // trueES5 環境での注意点
ES6 のクラス構文が使えない環境では、prototype チェーンを手動で設定する必要があります。現在のモダンブラウザや Node.js では気にする必要はありませんが、古い環境をサポートする場合は Babel などのトランスパイラを使いましょう。