TypeScript Awaited:一招搞定异步函数返回值类型
在日常开发中,我们经常会写一些异步函数,它们的返回值通常是一个 Promise
。如果我们想要获取 Promise
内部的最终类型,该怎么做呢?
TypeScript 在 4.5 版本中引入了一个内置工具类型:Awaited<T>
,用来帮我们安全、方便地提取出 Promise
中的值的类型。
一、Awaited 的定义
在 lib.es2022.d.ts
中,Awaited
的定义大致如下:
type Awaited<T> =T extends null | undefined ? T :T extends object & { then(onfulfilled: infer F, ...args: any): any } ? F extends (value: infer V, ...args: any) => any? Awaited<V>: never: T;
简单理解就是:
如果传入的是
Promise
,它会递归“拆解”出内部的类型;如果传入的不是
Promise
,直接返回原始类型;对
null
和undefined
会特殊处理,保持不变。
二、Awaited 的作用
主要作用就是:获取异步函数返回值的最终类型。
举个例子:
type T1 = Awaited<Promise<string>>;
// T1 = stringtype T2 = Awaited<Promise<Promise<number>>>;
// T2 = numbertype T3 = Awaited<string>;
// T3 = string(不是 Promise,直接返回原始类型)type T4 = Awaited<null>;
// T4 = null
可以看到,不论 Promise
嵌套多少层,Awaited
都能帮你“剥开洋葱”,直到拿到最终的类型。
三、和 ReturnType 的结合使用
在实际开发中,我们通常会配合 ReturnType
使用 Awaited
。
例如,一个异步函数:
async function fetchData() {return { id: 1, name: "Lin" };
}
如果我们直接用 ReturnType
:
type Result1 = ReturnType<typeof fetchData>;
// Result1 = Promise<{ id: number; name: string }>
得到的类型是 Promise
包裹的对象。
但如果我们希望拿到真正的返回值类型,就可以这样:
type Result2 = Awaited<ReturnType<typeof fetchData>>;
// Result2 = { id: number; name: string }
这在写工具库或者封装 API 类型时非常有用。
四、应用场景举例
封装请求函数的返回值类型
async function getUser() {return { id: 1, username: "test" }; }type User = Awaited<ReturnType<typeof getUser>>; // User = { id: number; username: string }
2.处理多层 Promise 的情况
type T = Awaited<Promise<Promise<Promise<boolean>>>>; // T = boolean
3.兼容异步链式调用的返回值
declare function foo(): Promise<number>; declare function bar(x: number): Promise<string>;async function run() {const result = await foo().then(bar);// result 推导为 string }
Awaited
能确保推导出来的类型就是最终await
后的类型。
五、实战案例
1. 配合 axios 获取接口返回类型
在项目中我们常常会这样封装请求:
import axios from "axios";async function getUserInfo() {const res = await axios.get<{ id: number; name: string }>("/api/user");return res.data;
}
如果我们想要直接拿到 getUserInfo
的返回值类型:
type User = Awaited<ReturnType<typeof getUserInfo>>;
// User = { id: number; name: string }
这样一来,User就是接口返回的数据结构类型,拿来在 Vue/React 里定义状态非常方便。
2. 配合 fetch 使用
使用 fetch
时,返回的也是 Promise
:
async function getPosts() {const res = await fetch("/api/posts");return res.json() as Promise<{ id: number; title: string }[]>;
}
获取最终类型:
type PostList = Awaited<ReturnType<typeof getPosts>>;
// PostList = { id: number; title: string }[]
3. 多层 Promise 自动剥离
有些工具函数可能返回嵌套的 Promise:
type Multi = Promise<Promise<string>>;type Result = Awaited<Multi>;
// Result = string
不管嵌套多少层,Awaited
都能直接帮你拿到最终的类型。
六、总结
Awaited<T>
是 TypeScript 4.5 引入的工具类型,用于提取Promise
最终返回的值类型。实际开发中,尤其是 接口请求函数、异步工具函数,配合
ReturnType
使用最常见。在封装 API 类型、结合 axios/fetch 时,能让类型推导更智能、更简洁。
一句话记住:
Awaited<T>
= 拆开 Promise
,得到真实的返回类型。