【初心者向け】TypeScript: 非同期catchの型エラーでスマートなエラー処理
TypeScriptにおける非同期catchでの型付きエラーの使用方法
従来のJavaScriptでは、catch
ブロック内のエラーはError
型としてのみ扱われていました。しかし、TypeScriptでは、より詳細な型情報に基づいたエラーハンドリングが可能になります。これが型付きエラーと呼ばれるものです。
型付きエラーの利点
型付きエラーを使用する利点は以下の通りです。
- コードの信頼性が向上する: 型チェックによって、誤ったエラー処理を防ぐことができます。
- より適切なエラーハンドリングが可能になる: エラーの種類に応じて、適切な処理を実行することができます。
- エラーの種類を特定しやすくなる: エラーオブジェクトの型情報を確認することで、具体的なエラーの種類を判断することができます。
型付きエラーを使用するには、catch
ブロックの引数に型パラメーターを指定します。この型パラメーターには、Error
型のサブクラスまたは、独自に定義したエラー型を指定することができます。
以下の例は、MyError
という独自エラー型を定義し、catch
ブロックで型パラメーターとして使用する方法を示しています。
class MyError extends Error {
constructor(message: string) {
super(message);
}
}
async function myFunction(): Promise<number> {
try {
// 非同期処理を行う
if (someCondition) {
throw new MyError('予期しないエラーが発生しました');
}
return 10;
} catch (error: MyError) {
// MyError型のエラーが発生した場合の処理
console.error(error.message);
return 0;
} catch (error) {
// その他のエラーが発生した場合の処理
console.error('予期せぬエラーが発生しました:', error);
return -1;
}
}
この例では、myFunction
関数が非同期処理を行い、someCondition
が真の場合にMyError
型のエラーをスローします。catch
ブロックでは、まずerror
変数にMyError
型を指定することで、MyError
型のエラーが発生した場合のみ、その後の処理を実行するようにしています。
class MyError extends Error {
constructor(message: string) {
super(message);
}
}
class NetworkError extends MyError {
constructor(message: string) {
super(message);
}
}
class AuthError extends MyError {
constructor(message: string) {
super(message);
}
}
async function fetchUserData(userId: number): Promise<UserData> {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new NetworkError('ネットワークエラーが発生しました');
}
const data = await response.json();
if (data.error) {
throw new AuthError(data.error.message);
}
return data;
} catch (error: NetworkError) {
console.error('ネットワークエラー:', error.message);
return {
id: 0,
name: '',
email: '',
};
} catch (error: AuthError) {
console.error('認証エラー:', error.message);
return {
id: userId,
name: '',
email: '',
};
} catch (error) {
console.error('予期せぬエラー:', error);
return {
id: 0,
name: '',
email: '',
};
}
}
このコードでは、以下の点に注目してください。
- エラーが発生した場合でも、空のオブジェクトを返却することで、処理を継続できるようにしています。
- 具体的なエラーメッセージを取得して、ログ出力しています。
catch
ブロックでは、それぞれのエラー型に応じて、適切な処理を実行しています。fetchUserData
関数は、非同期処理を行い、NetworkError
またはAuthError
が発生する可能性があります。MyError
という基底エラークラスと、そのサブクラスであるNetworkError
とAuthError
を定義しています。
ジェネリック型を使用する
ジェネリック型を使用することで、catch
ブロックの型をより柔軟に定義することができます。具体的には、以下のようなコードになります。
async function myFunction<T extends Error>(...args: any[]): Promise<number> {
try {
// 非同期処理を行う
if (someCondition) {
throw new T('予期しないエラーが発生しました');
}
return 10;
} catch (error: T) {
// T型のエラーが発生した場合の処理
console.error(error.message);
return 0;
} catch (error) {
// その他のエラーが発生した場合の処理
console.error('予期せぬエラーが発生しました:', error);
return -1;
}
}
この例では、myFunction
関数はジェネリック型パラメーターT
を持ち、このパラメーターにはError
型のサブクラスを指定することができます。catch
ブロックでは、error
変数にT
型を指定することで、T
型のエラーが発生した場合のみ、その後の処理を実行するようにしています。
ジェネリック型を使用する利点は、以下の通りです。
- コードの可読性と保守性を向上させることができます。
- さまざまな種類のエラーをひとつの関数で処理することができます。
Promiseのthenとcatchメソッドを使用する
Promiseオブジェクトのthen
とcatch
メソッドを使用することで、エラーハンドリングを型安全に行うこともできます。具体的には、以下のようなコードになります。
async function myFunction(): Promise<number> {
return await Promise.resolve(10).then(
(value) => {
// 非同期処理が成功した場合の処理
return value;
},
(error: Error) => {
// 非同期処理が失敗した場合の処理
if (error instanceof MyError) {
console.error('MyError:', error.message);
return 0;
} else {
console.error('その他のエラー:', error);
return -1;
}
}
);
}
この例では、myFunction
関数はPromiseオブジェクトを返却し、then
とcatch
メソッドを使用して、非同期処理の成功と失敗を処理しています。catch
メソッドの引数にerror: Error
を指定することで、エラーオブジェクトを受け取ることができます。その後、instanceof
演算子を使用して、エラーの種類を判別し、適切な処理を実行することができます。
Promiseのthen
とcatch
メソッドを使用する利点は、以下の通りです。
- 非同期処理の成功と失敗を別々に処理することができます。
- コードが簡潔になり、読みやすくなります。
非同期エラーハンドリングライブラリを使用する
TypeScriptには、非同期エラーハンドリングを容易にするライブラリがいくつか用意されています。代表的なライブラリとしては、以下のようなものがあります。
これらのライブラリを使用することで、より洗練されたエラーハンドリングを行うことができます。
どの方法を選択すべきか
どの方法を選択すべきかは、具体的なユースケースや開発者の好みによって異なります。以下は、それぞれの方法を選択する際の指針です。
- より洗練されたエラーハンドリングを行いたい場合: 非同期エラーハンドリングライブラリを使用することを検討しましょう。
- コードを簡潔に記述したい場合: Promiseの
then
とcatch
メソッドを使用する方法がおすすめです。 - さまざまな種類のエラーを処理する場合: ジェネリック型を使用する方法がおすすめです。
- シンプルなエラーハンドリングの場合:
catch
ブロックの引数に型パラメーターを指定する方法がおすすめです。
これらの選択肢に加えて、状況によっては独自のエラーハンドリングロジックを構築することもできます。
重要なのは、エラーハンドリングを適切に行うことで、アプリケーションの信頼性を向上させ、予期しない問題が発生した場合でも、適切に処理できるようにすることです。
typescript