【TypeScript】型安全なエラーハンドリング - 実装パターン集

【TypeScript】型安全なエラーハンドリング - 実装パターン集

2024-11-10

2024-11-10

型安全なエラーハンドリング:実装パターン集

TypeScriptを使うと、型安全なエラーハンドリングを実現でき、エラー処理における見落としや予期しない動作を防ぐことが可能です。この記事では、TypeScriptでのエラーハンドリングにおいて型安全性を高めるための実装パターンを紹介し、堅牢で保守性の高いコードの実現を目指します。

TypeScriptで型安全なエラーハンドリングを行うメリット

型安全なエラーハンドリングにより、エラーの発生源やエラーデータの構造が明確になり、エラーの処理漏れや型の不一致を減らすことができます。これにより、実行時エラーが減り、予測可能な動作を持つコードを実現できます。

型安全なエラーハンドリングの主なメリット

  1. エラー内容の明確化
    エラーメッセージやエラーコードが型で定義されるため、エラー内容が明確になり、理解しやすくなります。
  2. コンパイル時の型チェック
    開発中にコンパイルエラーが出ることで、エラーハンドリングの不足やミスを事前に発見できます。
  3. 保守性の向上
    型に基づくエラーハンドリングを行うことで、将来の変更や拡張がしやすくなり、保守性が高まります。

型安全なエラーハンドリングの実装パターン

以下に、TypeScriptで型安全にエラーハンドリングを行うための主要なパターンをいくつか紹介します。

カスタムエラーの作成

TypeScriptでは、標準のErrorクラスを拡張してカスタムエラーを作成できます。カスタムエラーを使用することで、エラーの種類や詳細情報を明確に定義できます。

class NotFoundError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "NotFoundError";
  }
}
class ValidationError extends Error {
  constructor(public field: string, message: string) {
    super(message);
    this.name = "ValidationError";
  }
}
// 使用例
try {
  throw new ValidationError("email", "Invalid email format");
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(`Validation error on field: ${error.field}`);
  }
}

この例では、NotFoundErrorValidationErrorというカスタムエラーを定義しています。それぞれ異なるエラー内容を表現できるため、エラーハンドリングがしやすくなります。

Union型を用いたResultパターン

関数の戻り値としてUnion型を使い、Resultパターンを実装することで、成功と失敗の両方の結果を型安全に扱えます。これは、API呼び出しや非同期処理でよく使われる手法です。

type Result<T> = { success: true; value: T } | { success: false; error: Error };
function parseJSON<T>(jsonString: string): Result<T> {
  try {
    const parsed = JSON.parse(jsonString);
    return { success: true, value: parsed };
  } catch (error) {
    return { success: false, error: new Error("Invalid JSON format") };
  }
}
// 使用例
const result = parseJSON<{ name: string }>('{"name": "Alice"}');
if (result.success) {
  console.log("Parsed value:", result.value);
} else {
  console.error("Error:", result.error.message);
}

この例では、parseJSON関数の戻り値が成功か失敗かをsuccessプロパティで確認でき、型に基づいて処理を分けられるため、安全で読みやすいコードが実現できます。

Either型を用いたエラーハンドリング

Either型は、成功と失敗のどちらか一方の結果を表す型で、Left(失敗)とRight(成功)に分かれます。Either型を用いることで、エラーが発生する可能性がある処理を安全に行えます。

type Either<L, R> = { type: "left"; value: L } | { type: "right"; value: R };
function divide(a: number, b: number): Either<string, number> {
  if (b === 0) {
    return { type: "left", value: "Division by zero error" };
  }
  return { type: "right", value: a / b };
}
// 使用例
const result = divide(10, 0);
if (result.type === "left") {
  console.error("Error:", result.value);
} else {
  console.log("Result:", result.value);
}

このパターンにより、エラーメッセージや成功結果の処理が統一され、エラーハンドリングが簡潔に記述できます。

Option型によるNullチェック

Option型は、値があるかもしれないし、ないかもしれない状態を表現するための型で、Some(値がある)とNone(値がない)に分かれます。これにより、nullundefinedによるエラーを回避できます。

type Option<T> = { type: "some"; value: T } | { type: "none" };
function findUser(id: number): Option<{ id: number; name: string }> {
  const users = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];
  const user = users.find((u) => u.id === id);
  return user ? { type: "some", value: user } : { type: "none" };
}
// 使用例
const user = findUser(1);
if (user.type === "some") {
  console.log("Found user:", user.value.name);
} else {
  console.log("User not found");
}

この例では、ユーザーが見つからない場合にnoneを返すことで、nullundefinedのチェックを省略できます。

Try-Catchを活用したエラーハンドリング

JavaScriptの標準的なtry-catch構文も、TypeScriptでカスタムエラーや型チェックと組み合わせて利用することで、さらに型安全なエラーハンドリングが可能です。

async function fetchData(url: string): Promise<string> {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP
 error! status: ${response.status}`);
    }
    return await response.text();
  } catch (error) {
    if (error instanceof Error) {
      console.error("Fetch error:", error.message);
    } else {
      console.error("Unknown error occurred");
    }
    throw error; // 必要に応じて再スロー
  }
}
// 使用例
fetchData("https://api.example.com/data").catch((error) => {
  console.error("Error caught in main:", error);
});

この例では、fetchData関数内でエラーの詳細をログ出力し、必要に応じてエラーを再スローすることで、エラーを上位で処理することもできます。

型安全なエラーハンドリングのまとめ

TypeScriptを活用した型安全なエラーハンドリングは、コードの可読性や保守性を向上させ、予期しないエラーを減らす効果があります。カスタムエラーの作成や、ResultEitherOptionといったパターンを利用することで、柔軟かつ堅牢なエラーハンドリングが実現可能です。プロジェクトの特性やエラー処理の要件に応じて、これらのパターンを適切に組み合わせて活用しましょう。

Recommend