RTK Query自定义baseQuery中如何为API调用添加响应类型
RTK Query自定义baseQuery中如何为API调用添加响应类型
我来帮你搞定这个问题!在RTK Query的自定义baseQuery里,给内部的刷新token请求指定响应类型的思路和你创建mutation时的方式略有不同,下面我给你拆解两种类型安全的实现方式,再也不用依赖as断言啦~
核心思路:给baseQuery调用显式指定泛型参数
RTK的FetchBaseQuery本身是泛型函数,我们在调用它的时候可以直接传入响应数据的类型,TypeScript会自动推导refreshResult的类型,完全不需要手动做类型断言。
方式一:直接在调用baseQuery时指定泛型(最推荐)
这是最直接的方式,针对刷新token这个特定请求,显式告诉TypeScript它的响应结构:
优化后的关键代码片段
// 显式指定泛型:第一个参数是响应数据类型,第二个是错误类型 const refreshResult = await baseQuery<IApiResponse<RefreshTokenResponse>, FetchBaseQueryError>( { url: API_ROUTES.AUTH.REFRESH_TOKEN, method: "POST", body: { refreshToken: refreshToken } }, store, extraOptions ) if (refreshResult.data) { // 此时refreshResult.data的类型已经是IApiResponse<RefreshTokenResponse>,无需as断言 // 这里根据你的IApiResponse结构调整:如果是嵌套的data字段就用refreshResult.data.data,直接返回的话用refreshResult.data store.dispatch(setNewAccessToken(refreshResult.data.data)) result = await baseQuery(args, store, extraOptions); }
完整的baseQueryWithReauth代码(带类型优化)
const baseQueryWithReauth: BaseQueryFn< string | FetchArgs, unknown, FetchBaseQueryError > = async (args, store, extraOptions) => { let result = await baseQuery(args, store, extraOptions) const refreshToken = (store.getState() as RootState).auth.refreshToken; if (result.error && result.error.status === 401) { if (refreshToken) { // 给刷新token的请求指定明确的响应类型 const refreshResult = await baseQuery<IApiResponse<RefreshTokenResponse>, FetchBaseQueryError>( { url: API_ROUTES.AUTH.REFRESH_TOKEN, method: "POST", body: { refreshToken: refreshToken } }, store, extraOptions ) if (refreshResult.data) { // 类型安全,无需手动断言 store.dispatch(setNewAccessToken(refreshResult.data.data)) result = await baseQuery(args, store, extraOptions); } else { console.error("Failed to fetch new access token: ", refreshResult.error) store.dispatch(logOut()) } } else { console.warn("no refresh token found logging out"); store.dispatch(logOut()) } } return result }
方式二:封装一个带类型的刷新token请求函数(更易复用)
如果刷新token的逻辑在多个地方用到,你可以把它封装成一个单独的类型安全函数:
// 封装带类型的刷新token请求 const fetchNewToken = async ( refreshToken: string, store: BaseQueryApi, extraOptions: Record<string, unknown> ): Promise<BaseQueryResult<IApiResponse<RefreshTokenResponse>, FetchBaseQueryError>> => { return baseQuery<IApiResponse<RefreshTokenResponse>, FetchBaseQueryError>( { url: API_ROUTES.AUTH.REFRESH_TOKEN, method: "POST", body: { refreshToken } }, store, extraOptions ) } // 然后在baseQueryWithReauth里调用这个函数 const refreshResult = await fetchNewToken(refreshToken, store, extraOptions)
关键说明:和mutation中指定类型的区别
你平时在创建mutation时指定响应类型,是在API slice层面定义对外暴露的请求类型;而自定义baseQuery里的刷新token请求是内部自动触发的逻辑,不属于你定义的API slice,所以需要在调用baseQuery时直接指定泛型参数,让TypeScript识别这个内部请求的响应结构。
这样调整后,你的代码不仅类型完全安全,还能避免因手动断言带来的潜在错误,可读性也大大提升了~ 😊




