如何为异步封装请求函数标注返回类型,让useQuery自动推导类型
解决useQuery返回data类型为any的问题
你的核心问题在于当前的asyncWrapper没有利用TypeScript的泛型传递函数的参数和返回类型信息,导致TypeScript无法推导getQuestions的具体返回类型,最终useQuery的data只能是any。下面是具体的修复步骤:
1. 将asyncWrapper改为泛型函数
我们需要让包装器能够捕获传入处理函数的参数类型和返回类型,这样TypeScript就能完整追踪类型信息:
// 泛型版本的异步包装器 export const asyncWrapper = <TArgs = unknown, TResult = unknown>( handler: (args?: TArgs) => Promise<TResult> ) => { return async (args?: TArgs): Promise<TResult> => { try { const result = await handler(args); return result; } catch (err: any) { // 添加可选链避免err.response不存在时报错 if (err.response?.status === 401) { await sessionService.refreshToken(); // 刷新令牌后重试请求 const result = await handler(args); return result; } // 必须抛出非401的错误,否则useQuery无法感知请求失败 throw err; } }; };
这里的泛型TArgs代表处理函数的参数类型,TResult代表处理函数的返回类型,默认值设为unknown是为了保持兼容性。
2. 修正QuestionsType的类型定义
注意你原来的QuestionsType中answerOptions应该是数组类型(一个问题会对应多个选项),否则返回的数组数据会和类型不匹配:
export type QuestionsType = { answerOptions: { _id: string; answerText: string; isCorrect: boolean; }[]; // 添加数组标记 questionText: string; };
3. 优化getQuestions的定义
现在不需要手动指定getQuestions的返回类型,TypeScript会通过泛型自动推导。同时给axios的get请求指定响应数据类型,确保response.data的类型准确:
const getQuestions = asyncWrapper(async (difficulty: string) => { const token = localStorage.getItem("accessToken"); try { // 给axios.get指定响应类型为QuestionsType[] const response = await axios.get<QuestionsType[]>("/questions", { headers: { Authorization: token, }, params: { difficulty } // 假设需要将difficulty作为查询参数传递 }); return response.data; } catch (e) { throw new Error("Custom"); } });
4. 验证useQuery的类型推导
现在使用useQuery时,data会自动推导为QuestionsType[] | undefined(undefined是因为useQuery初始状态或请求失败时data可能为空):
// data类型自动推导为QuestionsType[] | undefined const { data } = useQuery(["quiz", "easy"], () => getQuestions("easy"));
额外注意点
- 不要忘记在
asyncWrapper的catch块中抛出非401的错误,否则useQuery会误判请求成功,无法触发错误状态。 - 如果你的
getQuestions不需要参数,可以将泛型TArgs设为void,或者直接不传参数。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

