TypeScript async awaitで非同期処理の失敗を扱う
APIの結果を待ってから画面に表示したいときは、asyncとawaitを使います。ただし、fetchはHTTPの404や500だけでは例外になりません。通信失敗とHTTPエラーを分けて扱います。
結果を待つ
type Product = { id: string; name: string };
const getProduct = async (id: string): Promise<Product> => {
const response = await fetch(`/api/products/${encodeURIComponent(id)}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return (await response.json()) as Product;
};awaitはPromiseの完了を待ちます。関数の戻り値はPromise<Product>です。
呼び出し側で失敗を扱う
try {
const product = await getProduct('p1');
console.log(product.name);
} catch (error: unknown) {
console.error(error instanceof Error ? error.message : '不明なエラー');
}通信できない場合、JSONの解析に失敗した場合、明示的に投げたHTTPエラーなどがcatchへ入ります。
複数の処理を待つ順番
前の結果を使う処理は順番に待ちます。一方、独立した2つの取得を順番に待つと、待ち時間が合計されます。
const [product, category] = await Promise.all([
getProduct('p1'),
getCategory('c1'),
]);getCategoryは別途定義した取得関数とします。両方必要で独立している場合はPromise.allで並列に待てます。どちらかが失敗すると、Promise.all全体が失敗として扱われます。
また、awaitを書き忘れると変数には結果ではなくPromiseが入ります。const product = getProduct('p1')のままproduct.nameを読むと型エラーになります。
as Productは受信したJSONの形を確認しません。外部APIを厳密に扱う場合は実行時の検証を追加します。