2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptにおけるエラーハンドリング設計:try-catch, throw, null許容戦略の最適化

Posted at

概要

エラーハンドリングは「落ちたらcatchすればいい」ではない。
それは**“予期される失敗をコントロール下に置き、予期されない例外を安全に隔離するための設計戦略”**である。

JavaScriptは例外処理が柔軟な分、無秩序なtry-catchや雑なnullチェックが多発し、
保守性の低いコードになりがちである。

本稿では、try-catchの責務分離、throw戦略、null/undefined許容の境界設計、エラーオブジェクトの設計までを含む、構造的なエラーハンドリングの戦略を解説する。


1. try-catch の最小粒度原則

// ❌ 粗すぎる例外ハンドリング(原因不明)
try {
  const user = JSON.parse(json);
  const name = user.name.toUpperCase();
  saveToDB(name);
} catch (e) {
  console.error('Failed');
}
// ✅ 粒度を最小化
let user;
try {
  user = JSON.parse(json);
} catch (e) {
  throw new Error('Invalid JSON format');
}
  • ✅ 例外は「どの処理で失敗したか」が明示されるように
  • 一つのtryブロックには一つの責務

2. throw戦略とカスタムエラー設計

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = 'ValidationError';
  }
}

function validateName(name) {
  if (!name) throw new ValidationError('Name is required');
}
  • throw は構造化された情報を投げる
  • Error クラスの継承により、型や原因でcatchを分岐可能

3. null / undefined の安全設計

// ❌ 曖昧なnull処理
if (user && user.profile && user.profile.avatar) {
  show(user.profile.avatar);
}
// ✅ オプショナルチェーン
show(user?.profile?.avatar);
  • ? を使うことで**意図的に「なければ無視」**を表現
  • ✅ ただし、「なければ失敗すべき」文脈では明示的な throw を使う

4. 関数としての失敗表現(Either風)

function parseJSON(str) {
  try {
    return { ok: true, value: JSON.parse(str) };
  } catch (e) {
    return { ok: false, error: e };
  }
}
const result = parseJSON(input);
if (result.ok) {
  use(result.value);
} else {
  log(result.error);
}
  • ✅ 例外を外に出さず、「結果として返す」ことで呼び出し側に制御権
  • ✅ 副作用の少ないAPI設計に有効

5. UI/UXにおけるエラー分離(境界設計)

try {
  const user = await fetchUser();
  render(user);
} catch (e) {
  renderErrorMessage('ユーザーの取得に失敗しました');
}
  • ✅ UIとロジックの責務を明確に
  • ✅ catchブロックはユーザーに示す最小限のUIエラーに限定

設計判断フロー

① このエラーは「予期される失敗」か? → null/undefined or 値で返す

② 「例外」として投げるべきか? → 開発者のバグ or 実行時異常の場合のみ

③ try-catch の粒度は適切か? → 単一の責務だけを囲んでいるか

④ catch内でロギング + 再throwが必要か? → 処理の境界を意識する

⑤ エラーオブジェクトは構造的か? → name/type/message を設計済か

よくあるミスと対策

❌ try 内部で複数の処理を抱え、catchでは何が原因か不明

→ ✅ tryの粒度を責務単位で分割し、catchで明示


throw new Error('X is missing') をただの文字列で処理

→ ✅ カスタムErrorクラスで分類と構造化を


❌ すべてのnullを例外としてthrowし、UXが壊滅

→ ✅ nullは"欠けてもよい"設計の場合、静かに無視 or fallbackする


結語

エラーハンドリングは「エラーをキャッチする技法」ではない。
それは**“失敗と異常を制御構造として設計し、責務とUXを守るための安全装置”**である。

  • try-catch の粒度を絞り、catch の責務を明確に
  • throw は例外であり、エラーではない
  • null許容と例外制御を文脈ごとに設計し分離する

JavaScriptにおけるエラーハンドリングとは、
“失敗の責任と通知の設計を通じて、堅牢性と理解可能性を両立させるための戦略である。”

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?