TypeScript/非同期/Lesson 07
高度なエラー処理 — Discriminated Union + Result<T, E> パターン
40分·theory
このチャプター
7/7
TypeScript
高度なエラー処理 — Discriminated Union + Result
2. Result
高度なエラー処理 — Discriminated Union + Result パターン
💡 なぜ学ぶべきなのか? — エラーを「値」として扱うとより安全になる
🎯
throw/catch は制御フローがジャンプします — 呼び出し側はシグネチャを見るだけではどのエラーをキャッチすべきか判断できません。
💼
Result パターンはエラーを**戻り値**として扱います。関数シグネチャに起こりうるエラーの種類が埋め込まれるため、処理漏れがコンパイル時に表面化します。
⚡
Discriminated Union (`type Result = Ok | Err`) でモデリングすることで、呼び出し側が `if (result.ok)` のように自然に分岐できます。
🔗
Rust・Go・Kotlin の Result/Either パターンと同じ思想 — 関数型プログラミングの標準的なツールです。
📈
`never` 型を使うことで、コンパイラが「exhaustive check」(すべてのケースを処理済みかどうか) を検証してくれます。
🏢 실무에서는
Next.js Server Action の戻り値の型を `Promise>` のように明示すると、クライアントコンポーネントは成功・失敗の両方の分岐を漏れなく処理しなければなりません。throw でエラーが流れる場合、クライアントは「どこで try/catch を囲むべきだったか」と悩む必要がありますが、Result で返せばコンパイラがその心配を肩代わりしてくれます。
Discriminated Union · Result · Exhaustive Check
1. Discriminated Union — タグフィールドで分岐する型
タグ (kind) フィールドの値を絞り込むと、オブジェクト全体の形が絞り込まれます。
2. Result パターン
呼び出し元がエラー処理を忘れるとコンパイラがブロックします — if チェックなしに r.value を直接参照しようとすると拒否されます。
3. never による Exhaustive Check(網羅確認)
Event に新しいバリアントを追加したのに switch に case を書き忘れると、e が never ではなくなるため _exhaustive: never への代入がコンパイルエラーになります — 処理の抜け漏れをコンパイル時に検出できます。
4. throw vs Result — どちらをいつ使う?
throw は「異常系」用、Result は「想定される失敗」用です。
💡 💡 Result パターン実践ガイド
1. Result はライブラリなしで作る — 30行で十分
2. エラーも Discriminated Union で分類する
エラーの種類ごとに追加情報 (field · max) を正確な位置に持たせます。
3. never で exhaustive check を強制する
4. Result と throw の境界線
予測可能な失敗(バリデーション失敗 · 404 · 認証)→ Result。予測不能なバグ(null ポインタ · OOM)→ throw + グローバルハンドラー。
5. async + Result
想定された失敗は Result で返し、想定外のエラーは再スローします。
⚡ 実際に試してみよう — Result パターン
エラーを戻り値として処理する流れを体感します。
✏️ JS 코드
📟 コンソール出力
▶ 実行ボタンを押してください
⚠️ ブラウザのサンドボックスで実行 — console.log()のみ対応、alert/fetchは不可
確認クイズ
Discriminated Union の中に `default: const _: never = x;` パターンを置く理由は何ですか?
先に読むとよい概念: エラー処理 — catch の unknown を絞り込む
次のおすすめ: Reactの紹介