TanStack / TanStack/query

[vue-query] useQuery rejects spreading a queryOptions() result + override since v5.98.0

Open
#10,904 3 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
50.3k
Forks
4.2k
Avg merge
18h 25m
Merged PRs (30d)
200

Description

Describe the bug

Since @tanstack/vue-query v5.98.0, the documented pattern of spreading a queryOptions(...) result into useQuery and overriding a non-data-shaping option (e.g. enabled) no longer type-checks. Passing the same options object directly works; only the spread + override form fails.

This is a downstream continuation of #10525. That fix made queryOptions({ queryKey: computed(...) }) type-check again, but the branded queryKey (DataTag<...>) is still inconsistent with the other option properties once the result is spread into a fresh object literal, so useQuery inference fails with TS2769: No overload matches this call.

The most revealing part of the error cascade:

Types of property 'staleTime' are incompatible.
  ...
  Type 'readonly ["activity", "detail", string | null | undefined]' is not assignable to type
    '{ ...; [dataTagErrorSymbol]: Error; }'.
Your minimal, reproducible example
import { queryOptions, useQuery } from "@tanstack/vue-query"
import { computed, type MaybeRefOrGetter, toValue } from "vue"

const fooQueryOptions = (id: MaybeRefOrGetter<string | null>) =>
  queryOptions({
    queryKey: computed(() => ["foo", toValue(id)] as const),
    queryFn: async () => {
      const v = toValue(id)
      return v ? { id: v } : null
    },
  })

// ✅ OK — passed directly
useQuery(fooQueryOptions("1"))

// ❌ TS2769 since 5.98.0 (works on 5.97.0) — spread + override
useQuery({
  ...fooQueryOptions("1"),
  enabled: () => true,
})
Steps to reproduce
  1. Install @tanstack/vue-query@5.101.0 (or any version from 5.98.0 onward).
  2. Define a queryOptions(...) factory with a computed queryKey.
  3. Spread its result into useQuery({ ...opts, enabled: () => true }).
  4. Run tsc --noEmit / vue-tsc.
  5. TypeScript reports TS2769: No overload matches this call, bottoming out at the queryKey missing the dataTagSymbol / dataTagErrorSymbol brand.

Note: useQuery(opts) (passing the same options directly, without spreading or overriding) type-checks fine — only the spread + override form fails.

Expected behavior

Spreading a queryOptions(...) result and overriding enabled (or other non-data-shaping options) should type-check, as shown in the docs and as it did on 5.97.0:
https://tanstack.com/query/latest/docs/framework/vue/guides/query-options

How often does this bug happen?

Every time

Screenshots or videos

No response

Platform
  • TanStack Query version: broken on 5.98.0 – 5.101.0; last working 5.97.0
  • TypeScript version: 5.8+
  • Vue version: 3.5+
Additional context

Same class of regression as #10458 (fixed enabled) and #10525 (fixed queryKey on queryOptions), but it surfaces at the useQuery call site when spreading a queryOptions(...) result and overriding a property. Pinning to 5.97.0 produces zero type errors; any of 5.98.0 – 5.101.0 reproduces it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal reproduction at the queryOptions and useQuery entry points, running tsc --noEmit or vue-tsc against versions 5.97.0 and 5.98.0+. Trace the queryKey branding and option inference involved in the spread form; done means the documented spread-and-override example type-checks without TS2769 while direct useQuery(opts) remains valid.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.