throw 文で例外を投げる|JavaScript

throw 文を使うと、意図的にエラーを発生させることができます。入力値のチェックや、予期しない状態の検出など、プログラムを安全に保つために欠かせない機能です。

基本構文

throw;

throw の後には任意の値を指定できますが、通常は Error オブジェクトを投げます。

throw new Error('エラーが発生しました');

入力値のバリデーション

関数の引数が期待する値でない場合、早めにエラーを投げることで問題を明確にできます。

function divide(a, b) {
  if (b === 0) {
    throw new Error('0で割ることはできません');
  }
  return a / b;
}

try {
  console.log(divide(10, 0));
} catch (error) {
  console.error(error.message); // "0で割ることはできません"
}

エラーを投げずに処理を続けると、NaN や Infinity といった予期しない値が後続の処理に紛れ込む恐れがあります。

適切なエラー型を選ぶ

状況に応じた組み込みエラー型を使うと、エラーの原因がより明確になります。

function setVolume(level) {
  if (typeof level !== 'number') {
    throw new TypeError('level は数値で指定してください');
  }
  if (level < 0 || level > 100) {
    throw new RangeError('level は 0〜100 の範囲で指定してください');
  }
  console.log(`音量を ${level} に設定しました`);
}
TypeError

引数の型が間違っている場合に使用

RangeError

値が有効範囲外の場合に使用

throw で投げられるもの

throw は Error 以外の値も投げられます。

throw 'エラーです';       // 文字列
throw 404;               // 数値
throw { code: 'E001' };  // オブジェクト
throw null;              // null

ただし、Error オブジェクト以外を投げると stack プロパティが得られず、デバッグが困難になります。実務では必ず Error オブジェクトを使いましょう。

throw と return の違い

throw は関数の実行を中断してエラーを上位に伝播させます。return とは根本的に異なる動作です。

function checkAge(age) {
  if (age < 0) {
    throw new Error('年齢は0以上である必要があります');
  }
  return age;
}

throw が実行されると、その関数内の後続のコードは実行されません。また、呼び出し元で try-catch がなければ、プログラム全体が停止します。

再スロー(rethrow)

catch で一度エラーを捕捉した後、再度投げ直すことも可能です。

try {
  riskyOperation();
} catch (error) {
  console.error('エラーをログに記録:', error.message);
  throw error; // 再スロー
}

ログを記録しつつ、上位の呼び出し元にもエラーを伝えたい場合に使います。

条件付きでエラーを再スロー

特定のエラーだけを処理し、それ以外は再スローするパターンもよく使われます。

try {
  doSomething();
} catch (error) {
  if (error instanceof TypeError) {
    console.log('型エラーを処理しました');
  } else {
    throw error; // 他のエラーは上位へ
  }
}

こうすることで、関心のあるエラーだけを処理し、想定外のエラーは呼び出し元に任せることができます。