Home > Back-end >  rtk-query typescript for custom queryFn on API endpoint
rtk-query typescript for custom queryFn on API endpoint

Time:10-08

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[] };
    }
})
  • Related