Skip to content

fix(vue-query): align queryOptions with useQuery#11014

Open
tinas wants to merge 1 commit into
TanStack:mainfrom
tinas:fix/vue-query-queryoptions-match-usequery
Open

fix(vue-query): align queryOptions with useQuery#11014
tinas wants to merge 1 commit into
TanStack:mainfrom
tinas:fix/vue-query-queryoptions-match-usequery

Conversation

@tinas

@tinas tinas commented Jul 1, 2026

Copy link
Copy Markdown

🎯 Changes

queryOptions rejects some reactive options that useQuery accepts

I ran into this while using queryOptions in a Vue app. It rejects options that useQuery accepts without any problem. The case that actually blocked me was a reactive queryFn that returns skipToken, so the query stays idle until there's an input:

function pokemonOptions(name: MaybeRefOrGetter<string | null>) {
  return queryOptions({
    queryKey: computed(() => ['pokemon', toValue(name)]),
    queryFn: computed(() => {
      const current = toValue(name)
      if (!current) {
        return skipToken
      }
      return () => fetchPokemon(current)
    }),
  })
}

If I pass that same object straight to useQuery it type-checks. Through queryOptions it errors. So I can't move the options into a shared helper without the types getting in the way.

Reproduction: https://codesandbox.io/p/devbox/2yzjz5

The reason is that queryOptions and useQuery were built on two different option types. queryOptions only treated queryKey and enabled as reactive and required every other field (including queryFn) to be a plain non-reactive value, while useQuery treats every field as reactive, which is what makes a computed queryFn work.

This aligns queryOptions and infiniteQueryOptions with the option types useQuery and useInfiniteQuery already use, so if useQuery accepts it, queryOptions accepts it too.

Breaking change

The QueryOptions type is no longer exported, since it no longer exists. Use UseQueryOptions instead.


✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features

    • Improved TypeScript support for query options, including better handling of getters, reactive values, and skipToken.
    • Expanded typing coverage for query and infinite query helpers to match real usage more closely.
  • Bug Fixes

    • Fixed an incorrect type-check expectation around unsupported option properties.
    • Tightened queryKey validation so invalid getter-based key shapes are now rejected consistently.
  • Refactor

    • Reorganized internal type exports to better separate query options from return types.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors Vue Query's type system by moving UseQueryOptions and UseInfiniteQueryOptions type definitions into queryOptions.ts and infiniteQueryOptions.ts respectively, removing the old QueryOptions type, consolidating queryOptions overloads, updating import paths across consumer files and index re-exports, and adjusting associated type tests.

Changes

UseQueryOptions/UseInfiniteQueryOptions Type Relocation

Layer / File(s) Summary
Define UseQueryOptions and consolidate overloads
packages/vue-query/src/queryOptions.ts
New UseQueryOptions mapped type replaces QueryOptions; UndefinedInitialQueryOptions now derives from it; queryOptions overloads consolidated to accept/return MaybeRefOrGetter<UseQueryOptions<...>>.
Define UseInfiniteQueryOptions in-file
packages/vue-query/src/infiniteQueryOptions.ts
New exported mapped UseInfiniteQueryOptions type built over InfiniteQueryObserverOptions, intersected with ShallowOption, replacing the prior external import.
Remove duplicate definitions from consumers
packages/vue-query/src/useQuery.ts, packages/vue-query/src/useInfiniteQuery.ts
In-file UseQueryOptions/UseInfiniteQueryOptions type definitions removed; types now type-imported from queryOptions.ts and infiniteQueryOptions.ts.
Update import paths and index exports
packages/vue-query/src/queryClient.ts, packages/vue-query/src/useBaseQuery.ts, packages/vue-query/src/useQueries.ts, packages/vue-query/src/index.ts
Import sources updated to new type locations; QueryOptions re-export removed; type re-exports regrouped between useQuery/queryOptions and useInfiniteQuery/infiniteQueryOptions.
Update tests
packages/vue-query/src/__tests__/queryOptions.test-d.ts, packages/vue-query/src/__tests__/queryOptions.test.ts, packages/vue-query/src/__tests__/useQueries.test-d.ts
Tests import UseQueryOptions from queryOptions.ts, add coverage for tagged queryKey spreading, getter-returned options, skipToken with computed queryFn, and reject per-field getter queryKey shapes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

Not applicable — this PR is a type-only refactor without new control flow or multi-component runtime interactions.

Suggested labels: package: vue-query

Suggested reviewers: TkDodo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: aligning queryOptions with useQuery.
Description check ✅ Passed The description matches the template and explains the change, checklist, and release impact, though the release-impact selection is incomplete.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/vue-query/src/queryOptions.ts`:
- Around line 105-109: Restore the missing getter overload in queryOptions so
`DefinedInitialQueryOptions` still supports `queryOptions(() => ({ initialData:
... }))` and preserves the defined-data inference used by `useQuery`; update the
`queryOptions` type signatures in `queryOptions.ts` to include the getter branch
alongside the existing `MaybeRefOrGetter` overload, and add a corresponding
getter-based type test to verify the “data is always defined” behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 439a8355-5965-438b-90fc-f7e0042dc49d

📥 Commits

Reviewing files that changed from the base of the PR and between d6798b5 and 7bfe047.

📒 Files selected for processing (11)
  • packages/vue-query/src/__tests__/queryOptions.test-d.ts
  • packages/vue-query/src/__tests__/queryOptions.test.ts
  • packages/vue-query/src/__tests__/useQueries.test-d.ts
  • packages/vue-query/src/index.ts
  • packages/vue-query/src/infiniteQueryOptions.ts
  • packages/vue-query/src/queryClient.ts
  • packages/vue-query/src/queryOptions.ts
  • packages/vue-query/src/useBaseQuery.ts
  • packages/vue-query/src/useInfiniteQuery.ts
  • packages/vue-query/src/useQueries.ts
  • packages/vue-query/src/useQuery.ts

Comment on lines +105 to +109
options: MaybeRefOrGetter<
UseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>
>,
): () => UndefinedInitialQueryOptions<
TQueryFnData,
TError,
TData,
TQueryKey
): MaybeRefOrGetter<
UseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== queryOptions overloads ==="
sed -n '76,115p' packages/vue-query/src/queryOptions.ts

echo
echo "=== useQuery type entry points ==="
sed -n '1,90p' packages/vue-query/src/useQuery.ts

echo
echo "=== existing type-test coverage for initialData ==="
rg -n "initialData" packages/vue-query/src/__tests__/queryOptions.test-d.ts packages/vue-query/src/__tests__/useQuery.test-d.ts

Repository: TanStack/query

Length of output: 6378


Restore the getter overload for DefinedInitialQueryOptions. queryOptions(() => ({ initialData: ... })) still needs a defined-initial-data overload; otherwise it falls back to the generic MaybeRefOrGetter<UseQueryOptions<...>> branch and loses the “data is always defined” inference that useQuery relies on. Add the getter case to the type tests too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/vue-query/src/queryOptions.ts` around lines 105 - 109, Restore the
missing getter overload in queryOptions so `DefinedInitialQueryOptions` still
supports `queryOptions(() => ({ initialData: ... }))` and preserves the
defined-data inference used by `useQuery`; update the `queryOptions` type
signatures in `queryOptions.ts` to include the getter branch alongside the
existing `MaybeRefOrGetter` overload, and add a corresponding getter-based type
test to verify the “data is always defined” behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant