I'm trying to factorize some of my RTK Query code. Most of my endpoints are simple CRUD endpoints for entities, so a lot of my .injectEndpoints() calls end up being exactly the same thing. I was thinking I could factorize it with some helper function like this one:
import { EndpointBuilder } from "@reduxjs/toolkit/dist/query/endpointDefinitions";
export const makeCrudEndpoints = <T, E extends string>(
entity: E,
path: string,
build: EndpointBuilder<any, any, any>
) => {
return {
[`add${entity}`]: build.mutation<T, Partial<T>>({
query: (body) => ({ method: "POST", url: path, body }),
}),
[`list${entity}s`]: build.query<T[], {}>({
query: () => ({
method: "GET",
url: path,
}),
}),
[`get${entity}`]: build.query<T, number>({
query: (id) => ({
method: "GET",
url: `${path}/${id}`,
}),
}),
} as const;
};
and use it like this:
const wallsApi = api.injectEndpoints({
endpoints: (build) => makeCrudEndpoints<Wall, "walls">("Wall", "walls", build),
});
export const { useGetWallQuery } = wallsApi;
But Typescript cannot find useGetWallQuery in wallsApi :
TS2339: Property 'useGetWallQuery' does not exist on type 'Api , { readonly [x: string]: MutationDefinition | QueryDefinition...> | QueryDefinition...>; }, "api", never, unique symbol | unique symbol>'.
So yeah, it got really complicated really quick, and I'm not sure what's the right thing to do next. I think the issue might be that the return type of the makeCrudEndpoints function is inferred as an index-type ({[p: string]: (EndpointDefinitionWithQuery<T extends Primitive ?.....) so I loose the type information of the keys.
I've tried to solve it using something like this, but the return type is not different.
return {
[`add${entity}` as `add${E}`]: build.mutation<T, Partial<T>>({
query: (body) => ({ method: "POST", url: path, body }),
}),
...
I'm aware that this has more to do with typescript than rtk-query, but I'm not sure where to start looking. Any thoughts, pointers?