使用baseQueryWithReauth下载文件时,queryFn返回值类型丢失问题
解决Redux Toolkit Mutation返回类型不匹配问题
问题场景
我通过封装queryFn实现mutation端点下载文件,对应的mutation代码如下:
downloadTournamentTRF: builder.mutation<{filename: string}, {id: Tournament["id"]}>({ queryFn: async ({id}, api, extraOptions, baseQuery) => { return baseQuery({ url: `/tournament/trf/${id}`, responseHandler: async (response) => { if (response.ok) { const filename = await saveResponseUsingHiddenElement(response); return {data: {filename}}; } else { return {error: {status: response.status, message: response.statusText}}; } }, cache: "no-cache" }); }}),
类型错误信息
这段代码触发了TypeScript类型检查错误:
TS2322: Type '({ id }: { id: number; }, api: BaseQueryApi, extraOptions: {}, baseQuery: (arg: string | FetchArgs) => MaybePromise<QueryReturnValue<unknown, FetchBaseQueryError, {}>>) => Promise<...>' is not assignable to type '(arg: { id: number; }, api: BaseQueryApi, extraOptions: {}, baseQuery: (arg: string | FetchArgs) => MaybePromise<QueryReturnValue<unknown, FetchBaseQueryError, {}>>) => MaybePromise<...>’. Type 'Promise<QueryReturnValue<unknown, FetchBaseQueryError, {}>>' is not assignable to type 'MaybePromise<QueryReturnValue<{ filename: string; }, FetchBaseQueryError, unknown>>’. Type 'Promise<QueryReturnValue<unknown, FetchBaseQueryError, {}>>' is not assignable to type 'PromiseLike<QueryReturnValue<{ filename: string; }, FetchBaseQueryError, unknown>>’. Types of property 'then' are incompatible. Type '<TResult1 = QueryReturnValue<unknown, FetchBaseQueryError, {}>, TResult2 = never>(onfulfilled?: ((value: QueryReturnValue<unknown, FetchBaseQueryError, {}>) => TResult1 | PromiseLike<...>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | ... 1 more ... | undefined) => Promise<...>' is not assignable to type '<TResult1 = QueryReturnValue<{ filename: string; }, FetchBaseQueryError, unknown>, TResult2 = never>(onfulfilled?: ((value: QueryReturnValue<{ filename: string; }, FetchBaseQueryError, unknown>) => TResult1 | PromiseLike<...>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | ... 1 mo...’. Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. Types of parameters 'value' and 'value' are incompatible. Type 'QueryReturnValue<unknown, FetchBaseQueryError, {}>' is not assignable to type 'QueryReturnValue<{ filename: string; }, FetchBaseQueryError, unknown>’. Type '{ error?: undefined; data: unknown; meta?: {} | undefined; }' is not assignable to type 'QueryReturnValue<{ filename: string; }, FetchBaseQueryError, unknown>’. Type '{ error?: undefined; data: unknown; meta?: {} | undefined; }' is not assignable to type '{ error?: undefined; data: { filename: string; }; meta?: unknown; }’. Types of property 'data' are incompatible. Type 'unknown' is not assignable to type '{ filename: string; }’.
当前baseQuery定义
我们使用的baseQueryWithReauth基于Redux Toolkit官方文档实现,类型定义如下:
const baseQueryWithReauth: BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError> = async (args, api, extraOptions) => { [...]};
问题根源在于BaseQueryFn泛型的第二个参数被固定为unknown,导致返回类型被限制,无法匹配mutation声明的{filename: string}类型。
解决方案
方案1:将baseQuery改为泛型类型
修改baseQueryWithReauth的类型定义,让它支持根据调用上下文推导返回数据类型:
const baseQueryWithReauth: BaseQueryFn< string | FetchArgs, unknown, FetchBaseQueryError, {}, // 保留原空对象的meta类型,可按需修改 {} // 保留原空对象的extraOptions类型 > = async (args, api, extraOptions) => { // 原有的重鉴权逻辑代码 };
或者进一步封装为显式泛型函数,类型推导更灵活:
const baseQueryWithReauth = <T = unknown>( args: string | FetchArgs, api: BaseQueryApi, extraOptions: {} ): Promise<QueryReturnValue<T, FetchBaseQueryError, {}>> => { // 原逻辑代码 };
方案2:在mutation中显式断言返回类型
如果不想修改baseQuery的泛型定义,可在mutation的queryFn中对返回结果做类型断言:
downloadTournamentTRF: builder.mutation<{filename: string}, {id: Tournament["id"]}>({ queryFn: async ({id}, api, extraOptions, baseQuery) => { const result = await baseQuery({ url: `/tournament/trf/${id}`, responseHandler: async (response) => { if (response.ok) { const filename = await saveResponseUsingHiddenElement(response); return {data: {filename}}; } else { return {error: {status: response.status, message: response.statusText}}; } }, cache: "no-cache" }); return result as QueryReturnValue<{filename: string}, FetchBaseQueryError, unknown>; }}),
核心原理
- 原
BaseQueryFn的第二个泛型参数固定为unknown,导致所有调用都只能返回unknown类型的数据,无法匹配mutation声明的具体类型。 - 将baseQuery改为泛型后,它可以根据每个mutation的期望返回类型自动推导;显式断言则直接告知TypeScript返回类型的兼容性,绕过类型检查的限制。
内容的提问来源于stack exchange,提问作者Ben Golding
相关产品推荐
相关产品推荐

