Search code examples
reactjstypescriptreact-typescriptreact-query

React query - useQuery() No overload matches this call


I am getting this two errors that I am unable to explain nor solve, can anyone help me debug this problems.

  1. startDateIndex is missing in type, while I have declared the type in UseWeatherOptions
  2. useQuery() No overload matches this call. Should I remove the config
export const getWeatherForecast = ({
  startDateIndex,
}: {
  startDateIndex: number;
}): Promise<IWeatherForecast[]> => {
  return axios.get(`api/WeatherForecasts?startDateIndex=${startDateIndex}`);
};

type UseWeatherOptions = {
  startDateIndex: number;
  config?: QueryConfig<typeof getWeatherForecast>;
};

// Property 'startDateIndex' is missing in type '{}' but required in type 'UseWeatherOptions'.ts(2741)
export const useWeather = ({ startDateIndex, config }: UseWeatherOptions = {}) => {
  // No overload matches this call.
  return useQuery({
    ...config,
    queryKey: ['weather', startDateIndex],
    queryFn: () => getWeatherForecast({ startDateIndex }),
  });
};


Solution

  • ad 1: startDateIndex is missing in type, while I have declared the type in UseWeatherOptions

    your type UseWeatherOptions defines startDateIndex as a number, so it's a required field. That means you can't initialize UseWeatherOptions to an empty object, because an empty object does not contain startDateIndex.

    To fix this, you can make startDateIndex optional by defining it as:

    startDateIndex?: number
    

    or provide a default value:

    export const useWeather = ({ startDateIndex, config }: UseWeatherOptions = { startDateIndex: 0 }) => {
    

    in which case startDateIndex will be 0 when you call useWeather() without parameters (if that's what you want).


    ad 2: useQuery() No overload matches this call. Should I remove the config

    You are using the wrong type. The options passed to useQuery are not of type QueryConfig, but of type UseQueryOptions.

    However, that interface has 4 generics, so if you want to provide an abstraction over useQuery that allows allows passing in all the options, you would need to make your function generic as well.

    I would usually not make such an abstraction, because it means every call to useWeather could potentially pass in all possible query options, some of which will not make sense if they are different for multiple calls (like cacheTime). Also, the minimal thing you would need to do is to Omit the queryFn and the queryKey, because you have that hardcoded. So something along these lines:

    function useWeather<
      TQueryFnData,
      TError,
      TData = TQueryFnData,
      TQueryKey = QueryKey,
    >(
      startDateIndex: number,
      options?: Omit<
        UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
        "queryKey" | "queryFn"
      >
    ) {
      return useQuery({
        ...options
        queryKey: ['weather', startDateIndex],
        queryFn: () => getWeatherForecast({ startDateIndex }),
      });
    }
    

    In most of the cases, it is a lot better to provide abstractions that only allow to pass in the options that you would really like consumers of your custom hook to pass in. Like, should the query run in an interval sometimes? Let them pass in refetchInterval: number, etc ...