TypeScriptのPromiseとは?API通信の型定義を初心者向けに解説

TypeScriptのPromiseとは?API通信の型定義を初心者向けに解説

 

TypeScriptのPromise<T>とは

TypeScriptのPromise<T>とは、非同期処理が最終的に返す値の型を指定する書き方です。API通信の結果に型を付けることで、レスポンスの中身をエディタの補完付きで安全に扱えるようになります。

少年A
fetchでAPI叩くとき、TypeScriptだと何が変わるの?
キノ
一番変わるのは「返ってきたデータの中身をちゃんと型で管理できる」ところだよ

この記事では、TypeScriptでAPI通信を扱うときに必ず出てくるPromise<T>について、fetchを使った実例をもとに解説します。ジェネリクスの基本がまだ不安な場合は、先にこちらの記事を読んでおくと理解しやすいです。

スポンサーリンク

なぜAPI通信で型定義が必要なのか

JavaScriptでfetchを使う場合、レスポンスの中身は基本的に何が返ってくるか分かりません。

// JavaScript
fetch("/api/users/1")
  .then(res => res.json())
  .then(data => {
    console.log(data.nmae); // typoしてもエラーにならず、実行するまで気づけない
  });

プロパティ名を打ち間違えても、実行してブラウザのコンソールを見るまで気づけません。TypeScriptでレスポンスに型を付けておけば、こうしたミスをコードを書いている段階で発見できます。

スポンサーリンク

Promise<T>の基本の書き方

非同期関数の戻り値には、Promise<型>という形で型を指定します。

type User = {
  id: number;
  name: string;
};

async function fetchUser(id: number): Promise {
  const res = await fetch(`/api/users/${id}`);
  return res.json();
}

これは「この関数は、最終的にUser型の値を返すPromiseを返す」という意味です。Promise<T>のTの部分に、ジェネリクスと同じ考え方で好きな型を指定できます。interfaceとtypeの使い分けに迷う場合は、こちらの記事も参考にしてください。

async/awaitと型推論

関数にasyncを付けると、戻り値は自動的にPromiseで包まれます。

async function getUser(id: number) {
  const res = await fetch(`/api/users/${id}`);
  return res.json(); // 戻り値の型注釈を省略しても、Promiseとして推論される
}

ただし、この書き方だと戻り値がPromise<any>になってしまい、結局anyのデメリット(型チェックが効かない)を引きずってしまいます。API通信では戻り値の型を省略せず、明示的に書くのが安全です。

Promise<any>とPromise<T>の違い

項目Promise<any>Promise<具体的な型>
レスポンスの型不明(何でも通る)明確
入力補完効かないプロパティ名まで補完される
typoの検出実行するまで気づけないコードを書いている段階で気づける

any全般との違いについては、こちらの記事でさらに詳しく解説しています。

実務でよくあるエラー

async function fetchUser(id: number): Promise {
  const res = await fetch(`/api/users/${id}`);
  const data = res.json();
  return data;
  // Type 'Promise' is not assignable to type 'User'.
}

これはres.json()の前にawaitを付け忘れているのが原因です。json()自体もPromiseを返すメソッドなので、awaitを忘れると「PromiseのままのPromise」を返そうとしてしまい、型が一致しなくなります。

Reactでの使用例

ReactでAPI通信を行う場合、useEffectの中で先ほどの関数を呼び出し、結果をstateに保存する形がよくあるパターンです。

const [user, setUser] = useState(null);

useEffect(() => {
  fetchUser(1).then(setUser);
}, []);

fetchUserの戻り値がPromise<User>と分かっているので、setUserに渡す値の型もエディタが自動でチェックしてくれます。実際にReactでAPI連携を実装する中で、この型のつながりのおかげでミスに何度も助けられました。

よくある質問

Q. Promise<T>とは何ですか?
A. 非同期処理が最終的に返す値の型を指定する書き方です。TはAPIレスポンスなど、実際に返ってくるデータの型に置き換えます。

Q. なぜasyncを付けるとPromise<any>になるのですか?
A. 戻り値の型注釈を省略した場合、TypeScriptが型を推論しきれず、anyとして扱われることがあるためです。明示的に型を書くことで防げます。

Q. fetchの型定義はどこに書けばいいですか?
A. fetchを呼び出す関数の戻り値にPromise<型>という形で書きます。レスポンスの形はtypeやinterfaceで別途定義しておくのが一般的です。

まとめ

  • Promise<T>は、非同期処理の戻り値に型を付ける書き方
  • 戻り値の型注釈を省略すると、Promise<any>になりやすいので注意
  • API通信の型を明示しておくと、Reactのstateと連携する際もミスに気づきやすくなる

Promiseの基本的な仕組みそのものはJavaScriptの機能なので、公式ドキュメントも参考になります。

MDN Web Docs:Using the Fetch API
TypeScript公式ドキュメント:Generics

少年A
awaitの付け忘れ、自分もやりそう…
キノ
エラーメッセージに「Promise」って単語が出てきたら、まずawaitの付け忘れを疑うといいよ

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です