プログラミング初心者でも安心!ESLintの`no-throw-literal`ルールをマスターしよう


ESLint の no-throw-literal ルールは、例外としてリテラル値をスローすることを禁止します。これは、エラーオブジェクト以外の値を throw キーワードを使用して例外としてスローすることを防ぐためのものです。

なぜこのルールが必要なのか?

リテラル値を例外としてスローすると、いくつかの問題が発生する可能性があります。

  • コードが読みづらくなる: リテラル値を例外としてスローすることは、コードを冗長で読みづらくします。
  • コードが脆弱になる: リテラル値は、予期しない方法で変更される可能性があります。これは、エラー処理のロジックが破損する可能性があります。
  • デバッグが困難になる: エラーメッセージにリテラル値しか含まれないため、エラーの原因を特定するのが難しくなります。

このルールをどのように遵守するか?

このルールを遵守するには、例外としてスローする場合は常に Error オブジェクトまたはそのサブクラスを使用する必要があります

以下に、このルールを遵守する例を示します。

try {
  // 何か処理を行う
} catch (error) {
  // エラー処理を行う
  console.error(error.message);
}

このルールの例外

このルールにはいくつかの例外があります。

  • サードパーティライブラリ: サードパーティライブラリがリテラル値を例外としてスローする場合は、このルールを無効にする必要がある場合があります。
  • テストコード: テストコードでは、リテラル値を例外としてスローすることが許可されています。これは、テストを失敗させるために必要な場合があります。

このルールを有効にする方法

このルールを有効にするには、ESLint 設定ファイルに次の行を追加する必要があります。

{
  "rules": {
    "no-throw-literal": "error"
  }
}


悪い例

function divide(x, y) {
  if (y === 0) {
    throw "Division by zero"; // リテラル値をスロー
  }
  return x / y;
}

try {
  divide(10, 0);
} catch (error) {
  console.error(error); // エラーメッセージに詳細情報がない
}

この例では、divide 関数は y が 0 の場合にリテラル値 "Division by zero" をスローします。これは、no-throw-literal ルールによって違反されます。

良い例

function divide(x, y) {
  if (y === 0) {
    throw new Error("Division by zero"); // Error オブジェクトをスロー
  }
  return x / y;
}

try {
  divide(10, 0);
} catch (error) {
  console.error(error.message); // エラーメッセージに詳細情報が含まれている
}

この例では、divide 関数は y が 0 の場合に Error オブジェクトをスローします。これは、no-throw-literal ルールに準拠しています。

test("should throw an error when dividing by zero", () => {
  expect(() => divide(10, 0)).toThrow(Error); // リテラル値をスローしてもテストが成功する
});


no-throw-literal ルールは、例外としてリテラル値をスローすることを防ぎ、コードの品質と保守性を向上させるのに役立ちます。しかし、このルールにはいくつかの例外があり、すべての状況で適用できるわけではありません。

そこで、この章では、no-throw-literal ルールの代替手段について説明します。

代替手段

no-throw-literal ルールの代替手段として、以下の方法が考えられます。

  1. カスタムエラークラスを使用する: より具体的なエラーメッセージを生成したい場合は、カスタムエラークラスを作成することができます。
  2. ログを使用する: どうしてもリテラル値を例外としてスローする必要がある場合は、ログを使用してエラー情報を記録することができます。ただし、これは最後の手段としてのみ使用してください。

各代替手段の詳細

以下に、各代替手段の詳細を説明します。

Error オブジェクトを使用する

function divide(x, y) {
  if (y === 0) {
    throw new Error("Division by zero"); // Error オブジェクトをスロー
  }
  return x / y;
}

try {
  divide(10, 0);
} catch (error) {
  console.error(error.message); // エラーメッセージに詳細情報が含まれている
}

カスタムエラークラスを使用する

class DivisionByZeroError extends Error {
  constructor() {
    super("Division by zero");
  }
}

function divide(x, y) {
  if (y === 0) {
    throw new DivisionByZeroError(); // カスタムエラークラスをスロー
  }
  return x / y;
}

try {
  divide(10, 0);
} catch (error) {
  console.error(error.message); // エラーメッセージに詳細情報が含まれている
}

ログを使用する

function divide(x, y) {
  if (y === 0) {
    console.error("Division by zero"); // ログを使用してエラー情報を記録
    return;
  }
  return x / y;
}

try {
  divide(10, 0);
} catch (error) {
  // エラー処理は行わない
}

どの代替手段を選択すべきか?

どの代替手段を選択すべきかは、状況によって異なります。一般的には、Error オブジェクトを使用するのが最良の方法です。ただし、より具体的なエラーメッセージを生成したい場合は、カスタムエラークラスを使用することができます。どうしてもリテラル値を例外としてスローする必要がある場合は、ログを使用する必要がありますが、これは最後の手段としてのみ使用してください。