10. エラー処理とモジュール

try ・ catch ・ throw でエラーを扱う。ファイルを分けて import ・ export でつなぐ。npm の最小限

📅 作成: 2026-10-09 / 更新: 2026-10-09

try ・ catch ・ finally

エラーが起きると、処理はその場で止まります。try で囲んでおくと、止まる代わりに catch へ飛び、エラーを受け取って続きを決められます。finally は、エラーがあってもなくても最後に必ず実行されます。書き方は Java ・ C# と同じです。

try parsePrice("120") ✔ parsePrice("百円") ✖ この先は飛ばされる catch (e) e にエラーが入る どうするか決める finally 必ず実行される 後片付け 止まらずに次の処理へ エラー
エラーが起きた行から catch へ飛び、finally を通って次へ進む
function parsePrice(text) {
  const n = Number(text);
  if (Number.isNaN(n)) {
    throw new Error(`数値ではありません: ${text}`);
  }
  return n;
}
try {
  console.log(parsePrice("120"));
  console.log(parsePrice("百円"));
  console.log("ここは実行されない");
} catch (e) {
  console.log("捕まえた:", e.message);
} finally {
  console.log("後片付け");
}
console.log("処理は続く");
120
捕まえた: 数値ではありません: 百円
後片付け
処理は続く

どこでも捕まえられなかったエラーは、処理を止めて「Uncaught(捕まえられなかった)」と表示されます。01 章から見てきた表示です。

エラーの種類

JavaScript が自分で起こすエラーには、種類ごとの名前があります。どれも Error の仲間(子クラス)です。

Error TypeError型が合わない操作 ReferenceError無い名前を使った SyntaxError書き方の誤り RangeError範囲の外の値 自作のエラーextends Error
よく見るエラーと、自分で作るエラー
const samples = [
  () => null.length,
  () => undefinedName,
  () => JSON.parse("{壊れた JSON}"),
  () => new Array(-1),
];
for (const run of samples) {
  try {
    run();
  } catch (e) {
    console.log(`${e.name}: ${e.message}`);
  }
}
TypeError: Cannot read properties of null (reading 'length')
ReferenceError: undefinedName is not defined
SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)
RangeError: Invalid array length
メッセージ意味
Cannot read properties of null (reading 'length')null のプロパティは読めない(length を読もうとした)
undefinedName is not definedundefinedName は定義されていない
Expected property name or '}' in JSON at position 1JSON の 1 文字目の位置に、プロパティ名か } があるはずだった
Invalid array length配列の長さとして正しくない

自分のエラーを作る

Error を継承すると、自分用のエラーを作れます。instanceof で種類を見分けて、扱えるものだけを扱い、それ以外は throw e で外へ投げ直します。

class ValidationError extends Error {
  constructor(field, message) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
  }
}
function checkAge(age) {
  if (!Number.isInteger(age) || age < 0) {
    throw new ValidationError("age", `年齢が正しくありません: ${age}`);
  }
  return age;
}
for (const input of [20, -3, "abc"]) {
  try {
    console.log("OK:", checkAge(input));
  } catch (e) {
    if (e instanceof ValidationError) {
      console.log(`${e.field} の入力エラー → ${e.message}`);
    } else {
      throw e;
    }
  }
}
OK: 20
age の入力エラー → 年齢が正しくありません: -3
age の入力エラー → 年齢が正しくありません: abc

Java ・ C# から来た人へ: catch に型を書いて分けることはできません(catch (TypeError e) とは書けない)。1 つの catch で受けて、中で instanceof を使って分けます。また、メソッドが投げる例外を宣言する仕組み(Java の throws)もありません。

エラーの扱い方の方針

注意: try ・ catch で捕まえられるのは、try の中でその場で起きたエラーだけです。setTimeout などで後から動く処理の中のエラーは、外側の try では捕まりません。後から動く処理のエラーの扱い方は 11 章で見ます。

モジュール

プログラムが大きくなったら、ファイルを分けます。分けたファイルをモジュールと呼び、export で外に出したものだけを、別のファイルから import で使えます。この形式を ES Modules(ESM)と呼びます。Node.js では、拡張子を .mjs にするとこの形式になります(拡張子の決まりは 12 章)。

math.mjs export const TAX_RATE export function withTax export default formatYen export を付けないものは、外から見えない main.mjs import formatYen, { TAX_RATE, withTax } from "./math.mjs"; 使う名前を選んで取り込む
モジュールはファイルごとに中身が閉じていて、export したものだけが行き来する

次の 2 つのファイルを同じフォルダに置き、node main.mjs で実行します。

math.mjs

export const TAX_RATE = 0.1;

export function withTax(price) {
  return Math.floor(price * (1 + TAX_RATE));
}

export default function formatYen(n) {
  return `${n.toLocaleString()} 円`;
}

main.mjs

import formatYen, { TAX_RATE, withTax } from "./math.mjs";

console.log(TAX_RATE);
console.log(withTax(1000));
console.log(formatYen(withTax(12000)));
0.1
1100
13,200 円
書き方意味
export const X = …名前付き export。いくつでも書ける
export default …既定の export。1 つのファイルに 1 つだけ
import { X, Y } from "…"名前付き export を名前で取り込む
import 好きな名前 from "…"既定の export を取り込む。名前は取り込む側が決める
import * as m from "…"全部をまとめて 1 つのオブジェクトとして取り込む

all.mjs

import * as math from "./math.mjs";

console.log(Object.keys(math));
console.log(math.default(500));
[ 'TAX_RATE', 'default', 'withTax' ]
500 円

from の後ろのパスは、./ で始まる相対パスで書き、拡張子も省略しません。

モジュールの中は、ファイルごとに閉じている

モジュールの一番外側で作った変数は、var であってもグローバルにはなりません。07 章で見た「名前のぶつかり」が起きなくなります。また、モジュールの中は自動で strict モードです。

scope.mjs

var secret = "モジュールの中";
console.log(globalThis.secret);
console.log(typeof secret);

function setTotal() {
  total = 10;
}
try {
  setTotal();
} catch (e) {
  console.log(`${e.name}: ${e.message}`);
}
undefined
string
ReferenceError: total is not defined

npm の最小限

ほかの人が作ったモジュールは、npm というしくみで取ってこられます。npm は Node.js と一緒に入っています。

npm init -y
npm install パッケージ名

入れたパッケージは、./ を付けずに名前だけで取り込みます。

import something from "パッケージ名";

ヒント: node_modules は大きくなりやすく、npm install でいつでも作り直せるので、Git などで管理するときは対象から外します。共有するのは package.json と package-lock.json です。

package.json には "type" という項目があり、.js のファイルをどちらの形式として読むかを決めます。もう 1 つの形式(CommonJS)と合わせて、12 章で扱います。