Skip to content

better type narrowing for initialDataΒ #3310

@TkDodo

Description

@TkDodo

when providing initialData directly on a query, the type of data is guaranteed to be TData, not TData | undefined:

const { data } = useQuery(['test'], () => Promise.resolve('test'), { initialData: 'something' })

// 🚨 Object is possibly 'undefined'.(2532)
data.toUpperCase()

TypeScript playground

ideally, we could narrow the type when initialData is provided. This only works for initialData because initialData is executed in the constructor of the query, and because it is synchronous. Also, it can only work on v4 because in v3, undefined is technically still valid for the TData generic, so we cannot remove it from the union. In v4, undefined is illegal for successful queries, so that would now work.

Keep in mind that initialData can also be a function that returns TData | undefined, so this should also narrow if the function returns TData.

It does NOT work for:

  • placeholderData, because that will revert back to undefined when a query errors
  • initialData being provided globally, because TS cannot know that on an instance level. It needs to be explicitly passed to useQuery.
  • suspense or any other case because a query can be cancelled while it is initially fetching, in which case it will be reset to its initial state. queryClient.resetQueries also does that. Also, without network connection in the default network mode, the query will be in fetchStatus: 'paused' and will also not have data.

I guess we could potentially do this with another overload that has initialData provided and removes undefined from the result union, but we would also have do this for useQueries.
I would like to avoid having to add another generic to useQuery, as we already have four of them.

Because this is for v4, PRs should go to the beta branch please.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions