Search code examples
typescriptrtk-query

How do I make a query hook return type depend on parameter type using RTK query and typescript?


I'm making a program using React for the UI development. The program is meant to access the file system for settings so I run some server code in node and use RTK query to do the communication with that code.

Some of the server code reads a value from an xml file. I have these interfaces defined in the server code that define the type of the request and response parameters:

// define the key and value pairing for the file
export interface PersistentFileValues {
  initialValue: number;
  repaymentChanges: DatedValue[];
}

// queries should provide a key that matches the pairing
export interface GetPersistentFileValueRequestQuery {
  itemKey: keyof PersistentFileValues;
}

// define type that gets the value type given a key
export type PersistentFileValue<T extends keyof PersistentFileValues> =
  PersistentFileValues[T];

// make GetPersistentFileValueResponseBody depend on GetPersistentFileValueRequestQuery
export interface GetPersistentFileValueResponseBody<
  T extends GetPersistentFileValueRequestQuery
> {
  value: PersistentFileValue<T['itemKey']>;
}

If I use createApi, and have an endpoint called getPersistentFileValue, how do I do the typing so that the hooks figure out the return type based on the key provided as an argument?

Currently I have:

endpoints: (builder) => ({
    getPersistentFileValue: builder.query<
      PersistentFileValue<keyof PersistentFileValues>,
      GetPersistentFileValueRequestQuery
    >({
      query: (queryData) => {
        return {
          url: constructGetPersistentFileValueUrl(queryData), // appends the data as a string to the url
          method: 'get',
        };
      },
      transformResponse: (result, _meta, arg) => {
        const out = result as GetPersistentFileValueResponseBody<typeof arg>;
        return out.value;
      },
    }),
...

There don't seem to be any type errors. However, when I use the hook:

const { data: repaymentChanges } = useGetPersistentFileValueQuery({
  itemKey: 'repaymentChanges',
});

I find that the type of repaymentChanges is too generic and I get an error if I try to get the length property.

How can I type things so that the hooks give me access to the data with the right type? Is there a better way to do this?

Before this I was making an endpoint for each value accessed from the file, but that seems pretty clunky.


Solution

  • As RTK Query is mapping types internally to create those new function signatures, any kind of generics/overloads will be getting lost. Your best bet is taking the RTK Query-generated hook, wrapping it in your own function and providing overloads for that.