React-query: Incorrect types for suspense

Created on 19 Nov 2020  路  8Comments  路  Source: tannerlinsley/react-query

Describe the bug
I have been playing around with v2 and v3 to experiment for a new project, and have noticed that the returned type for useQuery is incorrect with suspense.

I am beginning to think there should be an aliased function with different return types for suspense.

To Reproduce

  1. Write any code that uses useQuery
const { data } = useQuery<Todo[]>('todos', getTodos);
  1. Notice that you can't use data in a typescript project without first checking if its undefined because the returned type is Todo[] | undefined

Most helpful comment

The only way to make this work is to create separate suspense hooks as the suspense option can be set globally. But I guess the data could still be undefined if enabled is set to false for example.

All 8 comments

but isn't that expected though? In the first render cycle, your status will be 'loading' so you have no data yet, thus data will be undefined. Only if your status goes to 'success', you will have data to use (at least this is how it is without suspense, not sure how suspense influences anything here).

Tagged unions discriminated by the status field were added in v3 - lots of discussions about that topic in this PR: https://github.com/tannerlinsley/react-query/pull/1108
and it was then done in this PR: https://github.com/tannerlinsley/react-query/pull/1247

Ah, you could be right. My understanding of suspense was that if the data isn't loaded, it "throws" a promise which bubbles up to the <Suspense /> and renders the fallback, and it wouldn't try rendering any of the data that isn't loaded yet.

Yeah when you use suspense, React Query throws an error while it's loading or if it failed, so the only case when it renders your component is when the request is already a success, so if your request can't return undefined the data will always be there.

I saw this same behavior in my app, I'm also using suspense, and I end up all the time adding a if (!data) return null before the render and at the beginning of each effect, memo or callback just to make TS don't think that data can be undefined, in practice, these conditions never work and data is never undefined.

ah okay, got it. so what we would need to do, on type level, is return T rather than T | undefined if the option suspense was set to true?

Yes, I should just read the docs I guess:

When using suspense mode, status states and error objects are not needed and are then replaced by usage of the React.Suspense component (including the use of the fallback prop and React error boundaries for catching errors)

@boschni is this doable on type level?

The only way to make this work is to create separate suspense hooks as the suspense option can be set globally. But I guess the data could still be undefined if enabled is set to false for example.

Yep 鈽濓笍

ah okay, got it. so what we would need to do, on type level, is return T rather than T | undefined if the option suspense was set to true?

@TkDodo I think this needs to be the signature when initialData is set as well, not just when suspense is set. See: https://github.com/tannerlinsley/react-query/discussions/1301

Was this page helpful?
0 / 5 - 0 ratings

Related issues

oukayuka picture oukayuka  路  4Comments

tiagofernandez picture tiagofernandez  路  3Comments

CreativeTechGuy picture CreativeTechGuy  路  3Comments

the133448 picture the133448  路  4Comments

ggascoigne picture ggascoigne  路  4Comments