Promise<T> 非同期型
最終更新:2026-10-22
Promise<T> 非同期型
非同期型は Promise<T> を軸に展開します。async 関数の戻り値の型は自動的に Promise で包まれ、await が値のレベルでそれを解きます。ツール型の Awaited<T> は型のレベルで同じことをします(ネストした Promise も最後まで解きます)。「Promise の中にどんな型が入っているか」が分かれば、非同期コードのすべての変数に正確な型が付きます。
| グループ | 設定と実践 |
|---|---|
| 種類 | 構文 |
| strict モード | 不要 |
ℹ️ 説明 エディタは TypeScript を JavaScript にトランスパイルして実行します(型チェックなし)。型チェック結果は各サンプルの出力を参照してください。
📝 構文
// async 関数:戻り値の型は常に Promise<T> で包まれる
async function fetchUser(id: number): Promise<User> {
const res = await getJson("/users/" + id); // await が Promise を一層解く
return res; // return される値の型は User
}
// Awaited<T>:型レベルの await
type A = Awaited<Promise<User>>; // User
type B = Awaited<Promise<Promise<User>>>; // User。ネストしていても最後まで解かれる
⚙️ パラメータ
| Promise<T> | ジェネリックな容器です。T は将来のいずれかの時点で得られる値の型。TS 組み込みで、async/await と併用するのに import は不要です |
|---|---|
| async | 関数の修飾子です。関数の本体の中で await が使えるようになり、戻り値は自動的に Promise で包まれます。普通の値 T は Promise<T> になり、すでに Promise なら二重には包まれません |
| Awaited<T> | 組み込みのツール型で、await の型レベルの効果を模倣します。Promise を解いて T を得て、ネストした Promise を再帰的に解き、Promise でない型はそのまま返します |
戻り値:async 関数の戻り値の型は Promise<T> です。関数の本体が普通の値 T を return しても Promise<T> を return しても、最終的な型は Promise<T> になります(Promise<Promise<T>> にはなりません)。
▶ サンプル
下のコードを編集して「試す」を押すと、トランスパイル実行結果を確認できます:
出力:
{"id":7,"title":"Write TypeScript notes","done":false}
todo#7 title="Write TypeScript notes" done=false
(トランスパイル後の実行出力。todo は await を経て Todo と推論されます。await を付けなければ手元にあるのは Promise<Todo> で、todo.id に直接アクセスすると型エラーになります)
💡 ポイント
ℹ️ 説明 async 関数の本体で return T と return Promise<T> は完全に等価で、型が Promise<Promise<T>> と積み重なることはありません。Awaited<T> はまさにこの規則をツール型にしたものです。
💡 ヒント Promise.all の結果の型はタプルです。Promise.all([p1, p2]) の型は Promise<[A, B]> で、各位置の型は独立に保たれます。1回の await で全部の値を取り、それぞれの型も正確です。
⚠️ 注意 async 関数の中で投げられた例外は同期的には投げられず、rejected Promise になります。await の箇所で try/catch するか .catch() をつなげる必要があり、漏れると unhandled rejection です。戻り値の型 Promise<T> 自体からは「失敗の可能性」が見えません。
🏷️ 関連設定と実践
💡 関連ケース
ケースは今後追加予定です。
📚 関連チュートリアル
❓ よくある質問
Q Awaited<T> は何のためのもので、普段使えますか?
A await の型レベルの効果を模倣します。Promise<T> は T に解け、ネストした Promise は最後まで解け、Promise でないものはそのまま返ります。日常的に直接使う機会は多くなく、組み込みの型定義の中(Promise.all、async 関数の戻り値の型など)に現れるほか、自作のツール型で「Promise を解く」必要があるときに使います。たとえば Unwrap<T> = Awaited<T> のように。
Q await を忘れるとどうなりますか?
A 手元にあるのは Todo ではなく Promise<Todo> です。.id にアクセスすると型エラーになり(strictNullChecks の下ではより明白)、実行時には「まだ終わっていないタスク」です。TS は自動的に await してくれません。Promise 型を見たら「await が必要か」とまず考えましょう。
Q async 関数の戻り値の型は手で Promise<T> と書くべきですか?
A 書く必要はありません。型推論が return 文から Promise<T> を導けます。手で書く利点は、公開 API の契約が明示され、実装を変えたときにシグネチャが先にエラーを出すことです。内部の小さな関数は推論に任せれば十分です。