I am fetching some data in React with useQuery from tanstack. This hook returns UseQueryResult<TData, TError> and tanstack nicely infers TData from the queryFn making the fetch, but I can’t make Typescript infer TError from the same function.
For more context:
Any errors returned from our backend respect the problem details spec, so the http client in the frontend parses api responses and returns IApiResponse with a valid IProblemDetails interface when a request fails.
export type IApiResponse<T> = BaseResponse &
(
| {
isError: false;
data: T;
}
| {
isError: true;
problem: IProblemDetails;
rawBody: unknown;
}
);
So I know the folowing function would either return data of T or IProblemDetails
export async function getData({resourceId}: {resourceId: string}) {
const res = await new ApiWithAuth().get<T>(
`api/resource/${resourceId}`
);
if (res.isError) {
return Promise.reject(res.problem);
}
return res.data;
}
For a query like this
const playlistQuery = useQuery(['get-user-playlist-by-id'], async () => {
const res = await getUserPlaylistById({ userId: userId!, playlistId });
if (res.isError) {
throw res.problem;
}
return res.data;
});
The result is typed like playlistQuery: UseQueryResult<UserPlaylist, unknown>
; it correctly knows the data returned, but not the error type when it fails. Both me and Typescript know that problem is IProblemDetails
when I throw res.problem
so why can’t useQuery infer TError from there?
From these docs I understand UseQueryResult.error
is populated and typed based on the promise rejected/error thrown in the queryFn call so I would expect playlistQuery: IProblemDetails
to be inferred like TData is inferred to be UserPlaylist
I looked at this question and this blog , but I am not using an error boundry or triggering a side effect with onError
. Instead, different components of my page need to react locally to an error state, so I want a way for Typescript to know that when playlistQuery.isError
then playlistQuery.error
will hold an IProblemDetails
object.
How to achieve this without passing generics to useQuery or asserting the type? (both would be cumbersome and not typesafe)