TypeScriptでtry catch finallyをマスター!エラー処理の基礎と例外処理の活用法
生徒
「プログラムを実行しているときに、急にエラーが出て止まってしまうことがあります。これを防ぐ方法はありますか?」
先生
「TypeScriptには、エラーが起きてもプログラムを安全に動かし続けるための try catch という仕組みがあります。さらに finally を使うと、エラーの有無に関わらず必ず実行したい処理を書くことができるんですよ。」
生徒
「最後に必ず実行する処理、ですか。例えばどんな時に使うんでしょうか?」
先生
「ファイルの片付けや通信の終了など、後始末が必要な場面で大活躍します。具体的な使い方を一緒に学んでいきましょう!」
1. TypeScriptのエラーハンドリングとは?
プログラミングをしていると、予期せぬトラブルが発生することがあります。例えば、存在しないファイルを読み込もうとしたり、インターネットの接続が急に切れたりする場合です。これをプログラミングの世界では例外(れいがい)と呼びます。例外が発生すると、通常プログラムはその場で止まってしまいます。これを防ぎ、適切に対応することをエラーハンドリングや例外処理と呼びます。
TypeScriptでは、このエラーハンドリングを効率的に行うために try、catch、finally という命令を使います。これらを組み合わせることで、エラーが起きそうな場所をあらかじめ囲っておき、もし問題が起きても別の処理に切り替えて、プログラム全体がクラッシュするのを防ぐことができるのです。初心者の方は、まず「エラーが起きた時のための予備ルートを作る作業」だと考えると分かりやすいでしょう。
2. tryとcatchの基本的な役割
まずは基本となる try と catch について説明します。try は日本語で「試す」という意味です。エラーが起きる可能性がある命令を、この try のブロックの中に記述します。そして、もし try の中でエラーが発生した場合、プログラムはすぐに中断され、隣にある catch ブロックに処理がジャンプします。
catch は「捕まえる」という意味で、発生したエラーの内容をキャッチして、その後の対応(ユーザーにメッセージを表示するなど)を記述します。これにより、画面が真っ白になったりアプリが強制終了したりするのを防ぎます。いわば、エラーというボールが投げられた時に、それを受け止めるグローブのような役割を果たしているのです。
try {
// エラーが起きるかもしれない処理
console.log("処理を開始します");
// ここでわざとエラーを発生させる例
throw new Error("トラブル発生!");
console.log("ここは実行されません");
} catch (error) {
// エラーが起きた時に実行される処理
console.log("エラーをキャッチしました");
}
処理を開始します
エラーをキャッチしました
3. finallyブロックの必要性と活用シーン
今回のメインテーマである finally について解説します。finally ブロックは、try の中での処理が成功したか、あるいはエラーが起きて catch に進んだかに関わらず、最後に必ず実行される場所です。なぜこのような場所が必要なのでしょうか。
例えば、あなたが料理をしている場面を想像してください。料理が成功しても、失敗して焦がしてしまっても、最後に必ず「火を消す」という後片付けをしなければなりません。プログラムも同じです。データの保存処理や通信、メモリの解放など、結果がどうあれ必ず完了させなければならない処理が存在します。もし catch の中にだけ後片付けを書いていると、成功した時にその処理が漏れてしまいます。逆に try の最後にだけ書いていると、エラー時に実行されません。これらを一箇所にまとめて、確実に実行させるのが finally の役目です。
4. 通信処理におけるfinallyの実践例
実際の開発でよくあるケースとして、サーバーからデータを取得する通信処理があります。通信を開始するときには、ユーザーに「読み込み中...」という表示(ローディング画面)を出しますが、データの取得が終わったら、成功しても失敗してもその表示を消す必要があります。ここで finally を使うと非常に綺麗に書けます。
let isLoading = false;
try {
isLoading = true;
console.log("ローディング表示を開始...");
// 擬似的なデータ取得処理
console.log("データを取得しています");
} catch (error) {
console.log("通信エラーが発生しました");
} finally {
isLoading = false;
console.log("ローディング表示を終了しました(必ず実行)");
}
ローディング表示を開始...
データを取得しています
ローディング表示を終了しました(必ず実行)
このように、成功・失敗のどちらのルートを通っても、最終的に isLoading を false に戻すことができます。これにより、画面にずっと「読み込み中」が出続けて操作できなくなる、といったバグを防ぐことができます。
5. ファイル操作やリソースの解放
パソコンのファイルを読み書きしたり、データベースに接続したりする場合も finally は重要です。ファイルを一度開いたら、必ず「閉じる」という作業を行わなければなりません。もし閉じ忘れると、他のプログラムがそのファイルを使えなくなったり、パソコンのメモリを無駄に消費し続けたりしてしまいます。
IT用語でこれをリソースの解放と言います。初心者の方には「借りたものを返す」というイメージで覚えてもらうと分かりやすいでしょう。finally を使えば、途中で計算間違いが起きようが、ネットワークが途切れようが、最後には必ず「返却」を行うことが保証されます。これは、安全で堅牢なシステムを作るためのプロの必須テクニックです。
function processFile() {
console.log("ファイルを開きます");
try {
console.log("ファイルの内容を解析しています");
// 何らかの複雑な処理
throw new Error("解析中に予期せぬエラー");
} catch (e) {
console.log("エラーを検知:処理を中断します");
} finally {
console.log("ファイルを安全に閉じました");
}
}
processFile();
ファイルを開きます
ファイルの内容を解析しています
エラーを検知:処理を中断します
ファイルを安全に閉じました
6. try catch finallyを入れ子にする場合
応用的な使い方として、try の中にさらに try を書く「入れ子(ネスト)」構造にすることもあります。これは、非常に大きな処理の流れの中で、特定の部分だけ個別にエラーハンドリングしたい場合に有効です。しかし、初心者のうちはあまり複雑にしすぎると、どこでエラーが起きてどこに飛ぶのかが分かりにくくなってしまいます。
まずは、一つの try に対して一つの catch と finally をセットにする基本形をしっかりマスターしましょう。TypeScriptのコードは上から下へ流れるのが基本ですが、例外処理が入るとその流れがジャンプします。この「ジャンプ」の動きを意識しながらコードを読むのが上達のコツです。finally はどんなに高くジャンプしても、必ず着地する場所だと覚えておきましょう。
7. throwを使った自作エラーの送出
これまではシステムが発生させるエラーを見てきましたが、自分からエラーを発生させることもできます。それが throw です。例えば、「入力された値がマイナスだったらエラーにする」という独自のルールを作りたい時に使います。throw で投げられたエラーも、同様に catch で受け取り、最終的に finally で後始末を行うことができます。
function checkAge(age: number) {
try {
if (age < 0) {
throw new Error("年齢にマイナスの値は入力できません");
}
console.log("年齢は " + age + " 歳ですね。登録します。");
} catch (error: any) {
console.log("【エラー報告】" + error.message);
} finally {
console.log("入力チェックを完了しました");
}
}
checkAge(-5);
【エラー報告】年齢にマイナスの値は入力できません
入力チェックを完了しました
この例では、年齢が不正な場合に自らエラーを投げ、catch ブロックでそのメッセージを表示しています。どんな場合でも最後のメッセージが表示されるため、ユーザーは何らかの処理が終わったことを確認できます。このように、自分でエラーを制御できるようになると、より高度なプログラミングが可能になります。
8. エラー処理を記述する際の注意点
最後に、エラー処理を書く際の重要なポイントをお伝えします。何でもかんでも try catch で囲えば良いというわけではありません。全くエラーが起きるはずのない場所にまで使ってしまうと、コードが読みづらくなり、動作が少しだけ重くなることもあります。本当に予測できない事態が起きそうな場所、あるいは後始末が絶対に不可欠な場所に絞って使うのがスマートです。
また、catch ブロックの中身を空にしてしまうのも危険です。エラーが起きたのに何もしないままだと、なぜプログラムが動かないのか原因が全く分からなくなってしまいます。最低限 console.log などでログを残す癖をつけましょう。そして、後始末が必要な場合は必ず finally を使い、一貫性のあるプログラムを目指してください。これらを意識するだけで、あなたの書く TypeScript のコードはぐっと信頼性の高いものになります。