RTKQuery queryFn结合TypeScript使用问题(v2已修复)
RTK Query TypeScript 类型错误解决方案
注意事项
RTKQuery v2 已完全重写为 TypeScript,此类型问题现已自动修复。以下为旧版本中的原始问题及解决方案。
原始问题
我用 TypeScript 编写了 RTK Query 的扩展接口,编译时 queryFn 的返回类型始终不匹配,代码如下:
import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query/fetchBaseQuery'; import { baseApi } from '../../../api/baseApi'; import { RootState } from '../../../redux/store'; import { UserResponse } from './userApiTypes'; export const extendedApi = baseApi.injectEndpoints({ endpoints: build => ({ getUser: build.query<UserResponse, void>({ queryFn: async (arg, api, extraOptions, baseQuery) => { const state = api.getState() as RootState; if (!state.auth.loginToken && !state.auth.refreshToken) return { error: { error: `UNAUTHORIZED`, status: `CUSTOM_ERROR` } as FetchBaseQueryError }; return await baseQuery(`/user/me`); }, }), }), }); export const { useGetUserQuery, useLazyGetUserQuery } = extendedApi;
编译错误信息
Type '(arg: void, api: BaseQueryApi, extraOptions: any, baseQuery: (arg: string | FetchArgs) => Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>) => Promise<...>' is not assignable to type '(arg: void, api: BaseQueryApi, extraOptions: any, baseQuery: (arg: string | FetchArgs) => Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>) => MaybePromise<...>'. Type 'Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>' is not assignable to type 'MaybePromise<QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>>'. Type 'Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>' is not assignable to type 'PromiseLike<QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>>'. Types of property 'then' are incompatible. Type '<TResult1 = QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>, TResult2 = never>(onfulfilled?: ((value: QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>) => TResult1 | PromiseLike<...>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | ... 1 more ......' is not assignable to type '<TResult1 = QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>, TResult2 = never>(onfulfilled?: ((value: QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>) => TResult1 | PromiseLike<...>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | ... 1 more ... | undefined...'. Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. Types of parameters 'value' and 'value' are incompatible. Type 'QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>' is not assignable to type 'QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>'. Type '{ error?: undefined; data: unknown; meta?: FetchBaseQueryMeta | undefined; }' is not assignable to type 'QueryReturnValue<UserResponse, FetchBaseQueryError, unknown>'. Type '{ error?: undefined; data: unknown; meta?: FetchBaseQueryMeta | undefined; }' is not assignable to type '{ error?: undefined; data: UserResponse; meta?: unknown; }'. Types of property 'data' are incompatible. Type 'unknown' is not assignable to type 'UserResponse'.ts(2322) endpointDefinitions.d.ts(37, 5): The expected type comes from property 'queryFn' which is declared here on type 'Omit<EndpointDefinitionWithQuery<void, (args: string | FetchArgs, api: BaseQueryApi, extraOptions: any) => Promise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>, UserResponse> & { ...; } & { ...; } & QueryExtraOptions<...>, "type"> | Omit<...>'
临时解决方法(不推荐)
移除 build.query 的泛型类型声明后可以编译,但会丢失全局强类型校验:
getUser: build.query({ // 移除了<UserResponse, void>泛型 queryFn: async (arg, api, extraOptions, baseQuery) => { const state = api.getState() as RootState; if (!state.auth.loginToken && !state.auth.refreshToken) return { error: { error: `UNAUTHORIZED`, status: `CUSTOM_ERROR` } as FetchBaseQueryError }; return await baseQuery(`/user/me`); }, }),
正确解决方案
问题核心是 baseQuery 返回的 data 类型为 unknown,无法自动推导为 UserResponse,以下两种方法可解决:
方案1:给 baseQuery 结果添加类型断言
先导入 QueryReturnValue 类型:
import { QueryReturnValue } from '@reduxjs/toolkit/dist/query';
再修改 queryFn 中的返回逻辑:
getUser: build.query<UserResponse, void>({ queryFn: async (arg, api, extraOptions, baseQuery) => { const state = api.getState() as RootState; if (!state.auth.loginToken && !state.auth.refreshToken) return { error: { error: `UNAUTHORIZED`, status: `CUSTOM_ERROR` } as FetchBaseQueryError }; // 给 baseQuery 返回结果添加类型断言 return (await baseQuery(`/user/me`)) as QueryReturnValue<UserResponse, FetchBaseQueryError, FetchBaseQueryMeta>; }, }),
方案2:显式指定 queryFn 的返回类型
同样需要先导入 QueryReturnValue,然后给 queryFn 声明返回类型:
getUser: build.query<UserResponse, void>({ // 显式指定 queryFn 的返回类型 queryFn: async (arg, api, extraOptions, baseQuery): Promise<QueryReturnValue<UserResponse, FetchBaseQueryError, FetchBaseQueryMeta>> => { const state = api.getState() as RootState; if (!state.auth.loginToken && !state.auth.refreshToken) return { error: { error: `UNAUTHORIZED`, status: `CUSTOM_ERROR` } as FetchBaseQueryError }; return await baseQuery(`/user/me`); }, }),
方案3:升级到 RTK Query v2
如开头所述,RTKQuery v2 已完全重写为 TypeScript,类型推导逻辑更完善,无需额外处理即可自动匹配类型。
内容的提问来源于stack exchange,提问作者Rychu
相关产品推荐
相关产品推荐

