What's the type of React Query's Error and how to handle different cases?
Asked Answered
R

7

24

I'm using React Query with typescript to fetch data in my project and I'm trying to use the error the useQuery hook returns to display a message describing the error if it exists like this :

{isError && (error)? <p className=" text-[#ff0000] text-center font-semibold">{error?.response.data.message}</p> : null}

I'm having a problem with the error type : enter image description here

How can I fix it, I couldn't find anything on the internet and if possible can anyone explain how to handle different thrown error with react query since you can throw anything in JS/TS

Raynell answered 20/5, 2022 at 15:47 Comment(3)
The answer depends on what else are you using. By default, without any other library, the error would be an Error, but since you are accessing error.response, it looks like you are using something like axios maybe? In that case, the error would be whatever axios throws on error.Arneson
@JakubKotrs yeah I'm using axios actually. can you please explain what do you mean by whatever axios throws on error? I'm kind of new to typescript and I don't usually deal with error handlingRaynell
axios-http.com/docs/handling_errors, the error that is in catch here is the error you are getting, find it's type.Arneson
T
43

error defaults to type unknown because your queryFn can throw anything, that's a javascript behaviour. throw 5 will give you number as your error type. There is no good way to assert that, so unknown is the best possible type. It's also what TypeScript does now per default since v4.4 (useUnknownInCatchVariables)

The best way to make sure that your app runs as you want is to narrow the type at runtime. if (error instanceof Error) does the trick, and the you can safely access error.message.

If you are using axios, the type is actually an AxiosError, and axios has an axios.isAxiosError(error) helper that checks for that and also narrows the type correctly.

The alternative is to provide generics to useQuery:

useQuery<Todo[], AxiosError>(['todos'], fetchTodos)

but this is bad for a couple of reasons:

  1. there are actually four generics, and you remove a bunch of features by only providing two of them
  2. There is no guarantee that your error will really be an axios error. For example, if you use select, and a runtime error happens in there (because of some faulty logic), your error will be a "normal" Error, but not an axios Error.

Alas, as you can throw anything in JS, unknown is the most correct type.

I'm also going into more details in my blog:

https://tkdodo.eu/blog/react-query-and-type-script

Tawannatawdry answered 25/5, 2022 at 7:37 Comment(0)
C
4

As @TkDodo has pointed out, you could provide generics to useQuery but it's not worth it, since you will lose the Type inference too.

However, as a workaround, I add the onError callback and type its error arg instead. TypeScript will infer the type of that error to the type I am expecting from useQuery.

Note that I am using Axios request & response interceptors for all requests that I use to format and throw my custom errors.


Example...


interface IPayload {
  someKey: string; // ETC
}

// The type of error expected from the response (also formatted by interceptor).
interface IApiError {
  message: string;
  description: string;
  statusCode: string | number;
}

export const useMyQuery = (payload: IPayload) => {
  const { data, isLoading, isError, error, refetch } = useQuery({
    queryKey: ['some', 'query-keys'],
    queryFn: () => API.fetchMyData(payload),
    // This does the trick
    onError: (err: IApiError) => err,
  });
};
Coquina answered 15/12, 2022 at 12:21 Comment(0)
U
1

My solution is too simple, so you can find out about the answer, but only for Axios:

const {
  data: location,
  isLoading: isLocationLoading,
  isError: isLocationError,
} = useQuery(
  {
    queryKey: ['location', user?.partner?.tourId],
    queryFn: () => getLocation('d'),
    onError: (err: AxiosError) => {
      console.log('Произошла ошибка при запросе:', err.response?.status)
    },
  }
)
Unseam answered 14/4, 2023 at 7:30 Comment(0)
B
1

Just add instanceof Error

if (error instanceof Error) return <div>{error.message }</div>
Brawner answered 24/6, 2023 at 18:53 Comment(0)
I
0

I had same issue with Typescript and react-query, same error Object is of type 'unknown'.

Installing this devDependency "@types/react-query" helped me somehow. I am using VS Code editor and I think that helped with type suggestions. This might help.

npm i --save-dev @types/react-query

Isogonic answered 25/10, 2022 at 16:49 Comment(0)
E
0

For Mutation only:

If you are using Axios for Api calls, use the following to get Axios type errors:

const error = mutation.error as AxiosError;

Now, the error object will not throw any object not found warning.

Exon answered 18/1, 2023 at 15:21 Comment(0)
M
0

In my case, I just used the as Error type assertion like this

<p>{(mutation.error as Error).message)}</p>

In your case, you can try

{isError && (error as Error)? <p className=" text-[#ff0000] text-center font-semibold">{(error as Error)?.response.data.message}</p> : null}
Moonmoonbeam answered 14/5, 2023 at 9:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.