概要
エラーハンドリングとは「失敗したときに止めること」ではない。
それは**“失敗の型と責任を明確にし、どこで何を補足し、どう伝達し、どう復旧するかを構造的に定義する設計”**である。
JavaScriptは try-catch
に頼るだけではなく、返却型(Result)・throwable型・UI伝播型など、多層的なエラーフローが可能。
正しいエラーハンドリングは、層ごとの責務を守り、ユーザーにも開発者にも安心を提供する。
1. エラーの責務分離:誰がどこで処理するべきか?
| 層 | 責務 |
|--------------|--------------------------------------|
| API/ドメイン | エラーを定義し、throwまたは返却 |
| ユースケース | エラーを分類し、状態やUIに変換 |
| UI層 | 表示制御、再試行、通知 |
2. 明示的なエラー構造の設計(Result型)
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
async function fetchUser(id: string): Promise<Result<User, 'NotFound' | 'NetworkError'>> {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) return { ok: false, error: 'NotFound' };
return { ok: true, value: await res.json() };
} catch {
return { ok: false, error: 'NetworkError' };
}
}
- ✅
throw
しない構造 → UIで確実に分岐処理可能 - ✅
ok: false
は構造的エラー → try-catch不要
3. 例外型(throw)と返却型(Result)の使い分け
- Result型 → UI/業務処理など **期待される失敗**
- throw型 → 不正入力 / 想定外バグ / 破壊を防ぐ例外
function parseJson(input: string): object {
try {
return JSON.parse(input);
} catch {
throw new Error('Invalid JSON');
}
}
- ✅ 「例外 = 想定外」「Result = 想定済み」という分類設計
4. 非同期エラーとキャンセルの分離制御
try {
const res = await fetch('/api', { signal: controller.signal });
} catch (e) {
if (e.name === 'AbortError') return;
notify('ネットワークエラーが発生しました');
}
- ✅ キャンセル(Abort)とエラーを分離
- ✅ UIや再試行に必要な情報として整理
5. エラー型の定義と分類戦略
type LoginError =
| { type: 'InvalidCredentials' }
| { type: 'TooManyAttempts'; retryAfter: number }
| { type: 'ServerError'; message: string };
- ✅ Union型で「エラーの種類」を明示的に管理
- ✅ UIは type で分岐 → 表示 / 再試行 / リダイレクト など制御
6. UI層でのエラーUI / 再試行 / アラート設計
if (!result.ok) {
switch (result.error.type) {
case 'InvalidCredentials':
showError('パスワードが間違っています');
break;
case 'TooManyAttempts':
showRetry(result.error.retryAfter);
break;
default:
showError('不明なエラーが発生しました');
}
}
- ✅ UI側の責務は「通知」「選択肢提示」「体験制御」
設計判断フロー
① そのエラーは「想定済みの失敗」か? → Result型で扱う
② 例外は「不正入力 / バグ / 想定外」か? → throwで構造を破壊
③ 非同期キャンセルと失敗が同一扱いになっていないか?
④ UIは「なぜ失敗したか」を受け取れる構造になっているか?
⑤ 再試行可能性 / ユーザー通知 / UI復帰が実装できる構造か?
よくあるミスと対策
❌ try-catch で全部握って何が起きたかわからない
→ ✅ 想定済みはResult型、例外は分類して構造管理
❌ UIで「エラー」としか表示されない
→ ✅ Union型で分類し、UIに伝える構造に
❌ API失敗で画面が白くなる or 無反応になる
→ ✅ 失敗時の状態反映・通知・再試行UIを用意
結語
エラーハンドリングとは「止める」ことではない。
それは**“失敗を分類し、意味を構造に落とし、層ごとに責務を分けて、安心して壊れるための戦略”**である。
- Result型とthrow型を設計的に使い分け
- UIと非同期の整合性を保ち
- 状態に失敗を織り込み、UXに転化する
JavaScriptにおけるエラーハンドリング戦略とは、
“壊れても制御可能で、意図を持って回復可能な、構造設計の最終防衛線”である。