query: [v5 beta] Type inference for `useQuery` breaks when using `queryOptions` util and `select`

Describe the bug

When using the new queryOptions util from react-query v5, type inference seems to be a bit fragile. For example when spreading the resulting options object and adding a select statement to the query, the resulting data type is incorrect. More interestingly, the type seems to be inferred correctly if we also set the type refetchInterval option. I haven’t tested around exactly which other options trigger this behaviour, but I believe this data point should be helpful enough in fixing the issue.

import { queryOptions } from '@tanstack/react-query'

const options = queryOptions({
  queryKey: ["key"],
  queryFn: () => Promise.resolve(1),
});

// Type inference breaks, so TS complains about return type of select()
const query1 = useQuery({
  ...options,
  select: (data) => data > 1
});

// Type inference works like it should, so query2.data has type boolean
const query2 = useQuery({
  ...options,
  select: (data) => data > 1,
  refetchInterval: 1,
});

// When inlining the query options, types are correct even without refetchInterval
const query3 = useQuery({
  queryKey: ["key"],
  queryFn: () => Promise.resolve(1),
  select: (data) => data > 1,
});

Your minimal, reproducible example

https://codesandbox.io/p/sandbox/festive-platform-0krnf3?file=%2Fsrc%2FApp.tsx%3A21%2C28

Steps to reproduce

  • Open the codesandbox
  • See the ts errors in the editor

Expected behavior

The correct data type should be inferred from the return type of the select function in useQuery.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

v5.0.0-alpha.34

Tanstack Query adapter

react-query

TanStack Query version

v5.0.0-alpha.34

TypeScript version

v5.0.4

Additional context

No response

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15

Most upvoted comments

No it doesn’t seem to work in the TS playground, but I think it’s broken in some way.

Try this barebones setup to reproduce:

mkdir tmp && cd tmp
npm init --yes
npm install typescript @tanstack/react-query@alpha @types/react

Paste this in a typescript file called tmp.ts and open project in vscode

import { queryOptions, useQuery } from '@tanstack/react-query'

const options = queryOptions({
  queryKey: ['key'],
  queryFn: () => Promise.resolve(1),
})

const query1 = useQuery({
  ...options,
  select: (data) => data > 1,
})

const query2 = useQuery({
  ...options,
  select: (data) => data > 1,
  refetchInterval: 1,
})

const query3 = useQuery({
  queryKey: ['key'],
  queryFn: () => Promise.resolve(1),
  select: (data) => data > 1,
})

query1 will have an error on select, query2 and query3 will have the correct types without errors.


For select, which changes the output type, you need a function I’m afraid

Yea I see that that’s the case at the moment, but it should be possible to write the types in a way that it works, as is evidence by my repro above where it works when refetchInterval is added. Something with the return type of queryOptions is making typescript trip. If a regular useQuery call can switch out the type when select is there, why shouldn’t one where we spread in queryOptions?

If you don’t know how to solve this, then I guess there’s not much more to do. But please don’t dismiss it as not reproducible or impossible to fix 🙏 It really is reproducible if you try my example above.

Thank you for the patience!

That one errors because you’re trying to set initialdData to a string while the queryFn returns a number though, right?

you’re absolutely right. I thought that the options can’t be narrowed anymore once it’s set to UndefinedInitialDataOptions, but seems like they can. Using the right type works, so that’s not an issue. Then the question is really: why doesn’t the same work for select 🤔