TypeScriptでAPIエラーを型安全に扱う!初心者向け例外処理と設計ガイド
生徒
「TypeScriptで外部のデータを読み込むとき、エラーが起きるとプログラムが止まってしまいます。どうすれば安全にエラーを扱えますか?」
先生
「それは例外処理という仕組みを使う解決できます。特にAPI通信では、どんなエラーが返ってくるか予測して型を付ける設計が重要ですよ。」
生徒
「型安全にエラーを扱うというのは、具体的にどう書けばいいのでしょうか?」
先生
「初心者の方でも安心して実装できる、エラーハンドリングの基本から応用まで順番に解説していきますね!」
1. エラーハンドリングと例外処理の基本
プログラミングにおけるエラーハンドリングとは、プログラムの実行中に予期しない問題が発生した際に、それを検知して適切に処理することを指します。これを放置すると、アプリが突然終了したり、画面が真っ白になったりして利用者が困ってしまいます。
特に例外処理と呼ばれる手法は、エラーを「例外(普通ではない事態)」として扱い、特別な命令を使ってキャッチします。TypeScriptでは主にtry-catchという構文を使って、エラーが起きそうな場所を囲い、もし問題が起きても安全な別の処理へ誘導する仕組みを作ります。
パソコンを触ったことがない方に例えるなら、これは「車の予備タイヤ」のようなものです。パンクというトラブルが起きることをあらかじめ想定して、予備のタイヤを準備しておくことで、走行不能になるのを防ぐのです。
2. try-catch構文の書き方と仕組み
まずは最も基本的なエラーの捕まえ方を学習しましょう。tryの中に「失敗するかもしれない処理」を書き、catchの中に「失敗したときに実行したい処理」を書きます。これにより、エラーが発生してもプログラム全体が止まることはありません。
try {
// ここにエラーが起きそうな処理を書く
console.log("処理を開始します");
throw new Error("通信に失敗しました"); // 意図的にエラーを発生させる
} catch (error) {
// エラーが起きたらここが動く
console.log("エラーをキャッチしました!");
}
実行結果は以下のようになります。
処理を開始します
エラーをキャッチしました!
ここで使っているthrow(スロー)という言葉は、エラーを「投げる」という意味です。投げられたエラーをcatch(キャッチ)が受け取るというイメージで覚えておくと分かりやすいでしょう。未経験の方でも、この「投げて受け取る」という流れが基本であることを押さえておけば大丈夫です。
3. APIエラーが発生する原因と重要性
API(エーピーアイ)とは、アプリケーション・プログラミング・インターフェースの略で、自分たちのアプリと外部のサーバーを繋ぐ窓口のようなものです。例えば、天気予報データを取得したり、SNSの投稿を読み込んだりする際に使われます。
API通信では、自分たちのコードが正しくてもエラーが起きることが多々あります。例えば「インターネットが繋がっていない」「相手のサーバーがメンテナンス中」「探しているデータが見つからない」といったケースです。これらをAPIエラーと呼びます。
TypeScriptを使う最大のメリットは、こうしたエラーが「どのような形(型)で返ってくるか」を事前に定義できる点にあります。型を決めておくことで、ついうっかり間違った処理を書いてしまうミスを防ぎ、安全な開発が可能になります。
4. catch句での型安全な扱い方
TypeScriptの古いバージョンでは、catchで受け取るエラーの型は自動的に何でも許容する型になっていました。しかし、最近ではより厳格に「中身が不明な型(unknown)」として扱われるようになっています。そのため、中身が何であるかを確認してから処理する必要があります。
try {
// 仮想のAPI通信
} catch (error: unknown) {
if (error instanceof Error) {
// errorが標準的なエラーオブジェクトならメッセージを表示
console.log("エラー内容: " + error.message);
} else {
// それ以外の場合
console.log("予期せぬエラーが発生しました");
}
}
ここで登場したinstanceof(インスタンスオブ)は、「その変数が指定した種類のデータかどうか」をチェックする命令です。このチェックを行うことで、プログラムは「あ、これはエラーメッセージを持っているデータだね」と確信を持って処理できるようになります。これを型ガードと呼び、型安全な設計の第一歩となります。
5. Result型パターンによる高度な設計
さらにプロらしい設計方法として、エラーを例外として投げるのではなく、「成功か失敗か」を戻り値として返すResult型というパターンがあります。これは、関数の結果として「成功データ」または「エラー情報」のどちらかが入っている箱を返すイメージです。
この方法の利点は、関数を呼び出す側が必ず「成功したかな?失敗したかな?」と確認を強制される点にあります。例外を投げる方法だと、ついついtry-catchを書き忘れてしまうことがありますが、戻り値として受け取る形式なら忘れる心配がありません。
type ApiResult =
| { success: true; data: string }
| { success: false; error: string };
function fetchUserName(id: number): ApiResult {
if (id === 1) {
return { success: true, data: "たろう" };
} else {
return { success: false, error: "ユーザーが見つかりません" };
}
}
const result = fetchUserName(2);
if (result.success) {
console.log("成功!名前は" + result.data);
} else {
console.log("失敗...理由は" + result.error);
}
このように、successという旗印(フラグ)を使って状態を分けることで、初心者でも迷わずに条件分岐を書くことができます。型によって中身が守られているため、開発効率も格段に上がります。
6. 独自のエラークラスを作って区別する
大きなシステムを作るときは、エラーの内容をもっと細かく分けたい場合があります。例えば「パスワード間違い」と「ネットワーク故障」は、ユーザーに伝えるメッセージを変えたいですよね。そんな時は、自分専用のエラーの種類(クラス)を作ります。
class NetworkError extends Error {
constructor(message: string) {
super(message);
this.name = "NetworkError";
}
}
try {
throw new NetworkError("インターネット接続を確認してください");
} catch (error) {
if (error instanceof NetworkError) {
console.log("通信環境のトラブルです: " + error.message);
}
}
class(クラス)というのは、データの設計図のようなものです。標準のErrorという設計図をベースにして、自分流のアレンジを加えた新しい設計図を作ることができます。これを継承(けいしょう)と呼びます。専門用語ですが、「基本の機能を引き継いでパワーアップさせること」だと理解してください。
7. 非同期処理におけるエラーハンドリング
API通信は、結果が返ってくるまで時間がかかる非同期処理(ひどうきしょり)という形で行われます。TypeScriptではasync(エィシンク)とawait(アウェイト)というキーワードを組み合わせて書くのが一般的です。この場合もtry-catchで囲むのが基本ルールです。
非同期処理とは、料理に例えると「お湯を沸かしている間に野菜を切る」といった、待ち時間を有効活用する動きのことです。通信が終わるのをじっと待つのではなく、他の作業をしながら結果を待ちます。そして、もしお湯が溢れた(エラーが起きた)ときは、すぐに火を止める(例外処理)必要があります。
非同期のコードは一見難しそうに見えますが、書き方の型が決まっているので、テンプレートとして覚えてしまうのが上達の近道です。何度も繰り返し書くことで、自然と指が覚えていくはずです。
8. エラーメッセージの多言語化とユーザー対応
プログラム内部で使うエラー内容と、実際にアプリを使うユーザーに見せるメッセージは分けるべきです。システム用語のまま「404 Not Found」と表示されても、パソコン初心者は驚いてしまいます。「ページが見つかりませんでした」と優しい日本語で表示するように設計しましょう。
そのためには、エラーオブジェクトの中にユーザー向けのプロパティを用意したり、エラーコードに基づいてメッセージを変換する辞書のような仕組みを作ったりします。型安全な設計をしていれば、こうした翻訳作業も安全に行えます。どのエラーに対してどのメッセージを出すべきか、TypeScriptが厳しくチェックしてくれるからです。
エラーは決して悪いものではありません。適切に扱えば、ユーザーを迷わせない親切なアプリケーションを作るための重要な手がかりになります。まずは簡単なtry-catchから始めて、一歩ずつ確実な設計を身につけていきましょう。