Search code examples
typescriptcastingreact-query

React Query UseQueryResult type narrowing


I'm using a list of queries with react-query to fetch "dependencies" and I want all the dependencies to load before rendering my component. I get the success state by checking all the deps as array and then act on it:

function DepsLoader() {
    const q1 = useQuery()
    const q2 = useQuery()
    const q3 = useQuery()
    const q4 = useQuery()

    const deps = [q1, q2, q3, q4]
    const allDone = deps.every(dep => dep.isSuccess)

    if (!allDone) return <Loading />

    return <Component q1={q1.data} q2={q2.data} q3={q3.data} q4={q4.data} />
}

In JS land, this works just fine. However, if I want to do the same in TS, I get an obvious error, that q1.data is Data | undefined because it is. Normally, one is supposed to narrow it down by first checking for q1.isSuccess directly, but in case of my list of dependencies, I don't want to do it manually (in real component, the list can be up to 9 queries atm).

I can as well cast it using q1={q1.data as Q1Type} but it's not ergonomic.

Is there any way to make TS recognise the fact that in reality all the queries are in success state and I have narrowed it down?


Solution

  • you would need to perform type narrowing with a user defined type guard when executing .every, because TypeScript doesn't know that without it.

    Here is a typescript playground showing the gist of it, based on this StackOverflow answer.