Promise<T> 异步类型
最后更新:2026-10-22
Promise<T> 异步类型
异步类型围绕 Promise<T> 展开:async 函数的返回值类型自动包一层 Promise,await 在值层面解开它;工具类型 Awaited<T> 在类型层面做同样的事(嵌套 Promise 也会解到底)。理解"Promise 里装的是什么类型",异步代码里的每个变量就都有精确类型。
| 分组 | 工程与实战 |
|---|---|
| 类型 | 语法 |
| 严格模式 | 不需要 |
ℹ️ 说明 编辑器将 TypeScript 转译为 JavaScript 后运行(不做类型检查);类型检查结果见示例 Output。
📝 语法
// 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 使用无需导入 |
|---|---|
| async | 函数修饰符:函数体内可用 await;返回值被自动包成 Promise——普通值 T 变 Promise<T>,已是 Promise 的不叠加 |
| Awaited<T> | 内置工具类型,模拟 await 的类型效果:解开 Promise 得到 T,递归解开嵌套 Promise,非 Promise 类型原样返回 |
返回值:async 函数的返回类型是 Promise<T>:函数体 return 一个普通值 T 或一个 Promise<T> 都可以,最终类型都是 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]>,每个位置的类型独立保留,await 一次同时拿到全部值且各自类型精确。
⚠️ 注意 async 函数里 throw 的异常不会同步抛出,而是变成 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 拿到的是 Promise<Todo> 而不是 Todo:访问 .id 会得到类型错误(strictNullChecks 下更明显),运行时则是"还没完成的任务"。TS 不会自动帮你 await——见到 Promise 类型先想"我需要 await 吗"。
Q async 函数的返回类型必须手写 Promise<T> 吗?
A 不必,类型推断能从 return 语句推出 Promise<T>。手写的好处是公共 API 的契约显式化、改实现时签名先报错;内部小函数交给推断即可。