You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:01:26