I am using a queryFn inside an API call using rtk-query and I cant figure out why typescript is complaining about the return value of the queryFn -- any help would be much appreciated.
This is a simplified version of my code
type Fields = {
name: string;
dob: string;
}
const fieldsApi = api.injectEndpoints({
endpoints: (build) => ({
getFields: build.query<{ data: Fields[] }, void>({
queryFn(arg, api, _, baseQuery) {
const { featureFlags } = api.getState() as RootState;
if (!featureFlags?.fieldsEnabled) {
return Promise.resolve([]);
}
return baseQuery({ url: "/fields" });
},
})
})
})
We need to bail out of requests if the featureFlag is not set (this works) and the calls to get the data are working correctly -- but typescript is not happy.
Posting the error below
Type '(arg: void, api: BaseQueryApi, _: {}, baseQuery: (arg: string | FetchArgs) => MaybePromise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>) => MaybePromise<...> | Promise<...>' is not assignable to type '(arg: void, api: BaseQueryApi, extraOptions: {}, baseQuery: (arg: string | FetchArgs) => MaybePromise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>>) => MaybePromise<...>'.
Type 'MaybePromise<QueryReturnValue<unknown, FetchBaseQueryError, FetchBaseQueryMeta>> | Promise<never[]>' is not assignable to type 'MaybePromise<QueryReturnValue<{ data: Fields[]; }, FetchBaseQueryError, unknown>>'.
Type '{ error?: undefined; data: unknown; meta?: FetchBaseQueryMeta | undefined; }' is not assignable to type 'MaybePromise<QueryReturnValue<{ data: Fields[]; }, FetchBaseQueryError, unknown>>'.
Type '{ error?: undefined; data: unknown; meta?: FetchBaseQueryMeta | undefined; }' is not assignable to type '{ error?: undefined; data: { data: Fields[]; }; meta?: unknown; }'.
Types of property 'data' are incompatible.
Type 'unknown' is not assignable to type '{ data: Fields[]; }'.ts(2322)
Do I need to do an as cast when using the queryFn or something like that?
CodePudding user response:
Do I need to do an as cast when using the queryFn or something like that?
Yes. The types for the redux-toolkit fetchBaseQuery
are defined in a strict way where the JSON data that is returned from the server has type unknown
(rather than defining it loosely with any
). So you do need to make an as
assertion.
return baseQuery({ url: "/fields" }) as { data: Fields[] };
You can get fancier about the return type but as { data: Fields[] };
will work just fine.
You've actually got two other errors here.
A base query returns an object which either has an error
property or a data
property. That is:
export type QueryReturnValue<T = unknown, E = unknown, M = unknown> =
| {
error: E
data?: undefined
meta?: M
}
| {
error?: undefined
data: T
meta?: M
}
The value of the data
property is what you would use as the generic for your endpoint.
Instead of:
getFields: build.query<{ data: Fields[] }, void>({
It should be:
getFields: build.query<Fields[], void>({
The queryFn
itself should return that QueryReturnValue
object with { data: Fields[] }
.
So this is not a valid return:
return Promise.resolve([]);
It needs to be:
return Promise.resolve({ data: [] });
Or without the Promise
: (you can return a promise but it's not required)
return { data: [] };
You could also return some sort of error.
Complete working code:
getFields: build.query<Fields[], void>({
queryFn(arg, api, _, baseQuery) {
const { featureFlags } = api.getState() as RootState;
if (!featureFlags?.fieldsEnabled) {
return { data: [] };
}
return baseQuery({ url: "/fields" }) as { data: Fields[] };
}
})