try / catch エラー処理と catch のナローイング
最終更新:2026-10-22
try / catch エラー処理と catch のナローイング
TS のエラー処理には2つのつらみがあります。1つは catch の err が厳格モードでは unknown であること(JS はどんな値でも throw できるため、コンパイラはそれが Error だと仮定できません)。ナローイングしなければ .message に触れられません。もう1つは「投げるかもしれない」ことが型のシグネチャに現れないことです。対処はこうです。unknown には instanceof でナローイングし、予期できる失敗には Result パターンへ切り替えて、成否を戻り値の型に直接書き込みます。
| グループ | 設定と実践 |
|---|---|
| 種類 | 構文 |
| strict モード | 不要 |
ℹ️ 説明 エディタは TypeScript を JavaScript にトランスパイルして実行します(型チェックなし)。型チェック結果は各サンプルの出力を参照してください。
📝 構文
// 1) unknown のナローイング
try {
risky();
} catch (err: unknown) {
if (err instanceof Error) console.log(err.message);
else console.log("unknown throw:", err);
}
// 2) Result パターン:ユニオン型で「成功か失敗か」を表す
type Result<T> = { ok: true; value: T } | { ok: false; error: string };
function attempt<T>(fn: () => T): Result<T> {
try { return { ok: true, value: fn() }; }
catch { return { ok: false, error: "failed" }; }
}
⚙️ パラメータ
| unknown | catch 変数の型です(厳格モードではこれが既定です)。何でも入れられますが、使う前には必ずナローイングが必要です。これが安全性の源です |
|---|---|
| instanceof | 最もよく使われるナローイングの手段です。err instanceof Error の後なら .message/.stack にアクセスでき、独自のエラークラスにも同じく有効です |
| Result<T> | 自作の戻り値の型です。{ ok: true; value: T } | { ok: false; error } の形で、呼び出し側はまず ok を判定しなければならず、判定した分岐の中で value か error のどちらか一方だけが手に入ります |
戻り値:Result パターンの戻り値の型は判別可能ユニオンです。ok が true のときだけ value があり、false のときだけ error があります。「失敗の可能性」が型に符号化され、呼び出し側は失敗の分岐を処理しないとコンパイルが通りません。
▶ サンプル
下のコードを編集して「試す」を押すと、トランスパイル実行結果を確認できます:
出力:
caught RangeError: not a positive integer: abc
7 0
{"ok":true,"value":42}
failed: invalid input
(トランスパイル後の実行出力。err は instanceof でナローイングした後でなければ .message にアクセスできません。ナローイングせずに直接 err.message と書くと error TS18046 になります)
💡 ポイント
ℹ️ 説明 JS はどんな値でも(数値、文字列、オブジェクト)throw できるため、TS は catch の err を Error ではなく unknown としました。これは useUnknownInCatchVariables(strict に含まれます)がもたらす保護で、存在しないかもしれない .message プロパティへの期待を防ぎます。
💡 ヒント ナローイングの手段は instanceof だけではありません。typeof err === "string"、"message" in err、isApiError(err) のようなカスタム型ガードも使えます。どれにも合致しない場合を処理する最後のフォールバック分岐を書いて、任意の throw の値をカバーしましょう。
⚠️ 注意 Result パターンは呼び出し側のコードを長くします(すべての呼び出し箇所で ok を判定するため)。よくある折衷案は、中核の業務の流れでは例外を続け、境界の層(ユーザー入力の解析、外部 API の呼び出し)では Result に変え、「予期できる失敗」を呼び出し側の明示的な処理に残すことです。
🏷️ 関連設定と実践
💡 関連ケース
ケースは今後追加予定です。
📚 関連チュートリアル
❓ よくある質問
Q catch の中で直接 err.message を使えないのはなぜですか?
A err の型が unknown だからです(JS は文字列を含めどんな値でも throw できます)。コンパイラは .message が存在することを保証できません。先にナローイングしましょう。err instanceof Error、typeof err === "string"、"message" in err などを使い、その後で安全にアクセスできます。
Q 独自のエラークラスはどうナローイングますか?
A extends Error で自分のクラスを定義し(たとえば ValidationError)、catch の中で err instanceof ValidationError と絞り込めば、独自のフィールド(err.field など)にアクセスできます。同じ try の中に複数のナローイング分岐を置け、具体的なものから一般的なものへ並べます。
Q いつ例外を使い、いつ Result を使うべきですか?
A 例外は「予期しない状況」(バグ、突然のネットワーク断)に向いており、呼び出し側は基本的に処理すべきではありません。Result は「予期できる失敗」(入力の解析、フォームの検証)に向いており、呼び出し側は必ず処理します。型が強制するからです。判断基準は「呼び出し側がこの失敗を受け取った後、意味のある次の一手を持つか」です。