Search code examples
redux-toolkitrtk-query

RTK-Query conditional typing of BaseQueryFn


In RTK, I'm using a custom baseQuery to wrap axios, following the general guidance here. However, I can't seem to figure out a way to use conditional typing for the BaseQueryArg type. For example, I'd like to be able to have my baseQuery function take in the following argument object:

{
  url: string
  method: "GET" | "PUT" | "POST" | "DELETE"
  body: any
}

But, rather than have body be any, or even a stricter union, I'd like to have it vary depend on the type of method. So, for example, if this was a simple function I would type it like so:

function myBaseQueryFunction<T extends "GET"|"POST">(args: {
  url: string
  method: T
  body: T extends "POST" ? {someBodyData: string} : null
}){
  // do the query
}

However, I can't seem to find any way to use that kind of typing for the function I pass to baseQuery and have it properly restrict the return types of of my query endpoints. Even if I don't use the BaseQueryFn utility type and, instead, manually type a function like the one above and then pass it to baseQuery, I still don't get the restriction on query's return that I want.

Is there anyway to do this kind of conditional typing of baseQuery?

Update

Per the accepted answer below, the simplest way to handle this is with a discriminated union on method, e.g.:

type BaseQueryDiscriminatedArg = 
  | {
      url: string
      method: "POST"
      body: {someBodyData: string}
     }
  | {
      url: string
      method: "GET"
      body?: null
     }

and then your BaseQueryFn type is just BaseQueryFn<BaseQueryDiscriminatedArg>


Solution

  • I assume this should be possible by using a discriminated union type for the argument, using method as the discriminator. Overloads or generics won't work, since TS cannot map correctly over those, hence the wrong resulting types.

    If you have more problems with that, a chat might help more. Just stop by in the Redux channel on Reactiflux