我正在尝试编译下面的 TypeScript 代码。
Tsc
对 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({ // changed here
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
之后发生了很多事情:
import { baseApi } from '../../../api/baseApi';
import { BaseResponse } from '../../../api/baseApiTypes';
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.tokens)
return { error: { error: `UNAUTHORIZED`, status: `CUSTOM_ERROR` } };
const result = await baseQuery(`/user/me`);
if (result.error)
return { error: result.error };
const baseResponseWithUser = result.data as BaseResponse<UserResponse>;
if (!baseResponseWithUser.data)
return { error: { error: `UNKNOWN_ERROR`, status: `CUSTOM_ERROR` } };
return { data: baseResponseWithUser.data };
},
}),
}),
});
export const { useGetUserQuery, useLazyGetUserQuery } = extendedApi;
我遵循了https://redux-toolkit.js.org/rtk-query/usage-with-typescript#typing-a-basequery所以我有一个
QueryReturnValue
类型
export type QueryReturnValue<T = unknown, E = unknown, M = unknown> =
| {
error: E
data?: undefined
meta?: M
}
| {
error?: undefined
data: T
meta?: M
}
然后在
queryFn
中我执行以下操作来解决 TS 编译错误。
const result = await baseQuery(`/user/me`);
return result as QueryReturnValue<UserResponse, unknown, unknown>;
然后我所做的是创建一个辅助函数以使其不那么冗长。
// Somewhere all api slices can import
export function someHelperForTS<T>(result: QueryReturnValue<unknown, unknown, unknown>) {
return result as QueryReturnValue<T, unknown, unknown>;
}
// Within queryFn
const result = await baseQuery(`/user/me`);
return someHelperForTS<UserResponse>(result);
我不喜欢它,因为我必须在 build.query (
build.query<UserResponse
) 和 someHelperForTS (someHelperForTS<UserResponse>
) 中声明相同的响应类型。