Skip to content

Conversation

@VedantMadane
Copy link

@VedantMadane VedantMadane commented Jan 15, 2026

Fixes #7892

The return type of queryOptions in vue-query was using types wrapped in MaybeRef which prevented TypeScript from seeing properties like queryFn, staleTime, placeholderData, etc directly on the returned object.

Solution: Created unwrapped types (DefinedInitialDataOptions and UndefinedInitialDataOptions) specifically for queryOptions, matching react-query's approach. These use QueryObserverOptions directly without MaybeRef.

Changes:

  • packages/vue-query/src/queryOptions.ts - Added unwrapped option types
  • packages/vue-query/src/tests/queryOptions.test-d.ts - Added test for queryFn accessibility

Testing: 17 type tests pass including new test verifying queryFn and staleTime are accessible on returned options object.

Summary by CodeRabbit

  • Tests

    • Added type-level assertions to verify query options expose queryFn, staleTime, and queryKey with correct types.
  • Refactor

    • Revised query options type definitions for clearer initial-data handling and improved type safety.
  • Chores

    • Added a changeset to publish a patch reflecting the type fixes.

✏️ Tip: You can customize this high-level summary in your review settings.

…eturn type

The return type of queryOptions was using types wrapped in MaybeRef, which
prevented TypeScript from seeing properties like queryFn directly on the
returned object.

This creates new unwrapped types (DefinedInitialDataOptions and
UndefinedInitialDataOptions) specifically for queryOptions return types,
matching the approach used in react-query.

Fixes TanStack#7892

Signed-off-by: Vedant Madane <6527493+VedantMadane@users.noreply.github.com>
@changeset-bot
Copy link

changeset-bot bot commented Jan 15, 2026

🦋 Changeset detected

Latest commit: 5ce8a62

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@tanstack/vue-query Patch
@tanstack/vue-query-devtools Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

This PR adds stricter TypeScript option types for vue-query's queryOptions, introducing DefinedInitialDataOptions and UndefinedInitialDataOptions, updates queryOptions overloads to use them, and adds a type-level test verifying queryFn, staleTime, and queryKey are exposed on the returned options object.

Changes

Cohort / File(s) Summary
Type Definitions
packages/vue-query/src/queryOptions.ts
Adds DefinedInitialDataOptions and UndefinedInitialDataOptions type aliases; updates queryOptions overload signatures to accept/return the new types (return augmented with queryKey: DataTag<...>); keeps a pass-through implementation signature.
Type Tests
packages/vue-query/src/__tests__/queryOptions.test-d.ts
Adds a TypeScript-only test asserting the queryOptions return value exposes queryFn, staleTime, and queryKey with appropriate types.
Release Notes
.changeset/fix-query-options-types-fix.md
Adds a changeset describing a patch that exposes queryFn and additional properties on the queryOptions return type.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • TkDodo
  • DamianOsipiuk

Poem

🐇
I dug a tunnel through the types tonight,
Found queryFn hiding just out of sight.
New aliases line the burrowed way,
Now options peek out at break of day. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: exposing queryFn and other properties on the queryOptions return type.
Description check ✅ Passed The description covers the main changes and references the linked issue, but the checklist items are not marked as completed.
Linked Issues check ✅ Passed The PR successfully addresses issue #7892 by introducing unwrapped types (DefinedInitialDataOptions and UndefinedInitialDataOptions) that expose queryFn and other properties on the queryOptions return type, matching react-query's approach.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the queryOptions return type issue: type definitions in queryOptions.ts, a type test, and a changeset entry. No out-of-scope modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/vue-query/src/queryOptions.ts (1)

56-80: Add UnusedSkipTokenOptions overload to match react-query's type safety for skipToken scenarios.

The queryOptions function is missing a critical overload. React-query's implementation includes a UnusedSkipTokenOptions overload (between DefinedInitialDataOptions and UndefinedInitialDataOptions) that prevents skipToken from being assigned to the queryFn property in conditional scenarios.

Vue-query's tests already use this pattern (e.g., queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5)), but without the intermediate overload, TypeScript cannot properly narrow the type for skipToken cases. Add the missing overload definition and overload signature to provide consistent type safety across all framework implementations:

export type UnusedSkipTokenOptions<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
> = Omit<
  QueryObserverOptions<TQueryFnData, TError, TData, TQueryFnData, DeepUnwrapRef<TQueryKey>>,
  'queryFn'
> & ShallowOption & {
  queryFn?: Exclude<
    QueryObserverOptions<TQueryFnData, TError, TData, TQueryFnData, DeepUnwrapRef<TQueryKey>>['queryFn'],
    SkipToken | undefined
  >
}

export function queryOptions<...>(
  options: UnusedSkipTokenOptions<...>,
): UnusedSkipTokenOptions<...> & {
  queryKey: DataTag<TQueryKey, TQueryFnData, TError>
}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf7f47e and cc06f3c.

📒 Files selected for processing (2)
  • packages/vue-query/src/__tests__/queryOptions.test-d.ts
  • packages/vue-query/src/queryOptions.ts
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: DogPawHat
Repo: TanStack/query PR: 9835
File: packages/query-core/src/__tests__/queryClient.test-d.tsx:242-256
Timestamp: 2025-11-02T22:52:33.071Z
Learning: In the TanStack Query codebase, the new `query` and `infiniteQuery` methods support the `select` option for data transformation, while the legacy `fetchQuery` and `fetchInfiniteQuery` methods do not support `select` and should reject it at the type level.
Learnt from: oscartbeaumont
Repo: TanStack/query PR: 9564
File: packages/solid-query-devtools/src/production.tsx:2-3
Timestamp: 2025-08-19T03:18:18.303Z
Learning: In the solid-query-devtools package, the codebase uses a pattern of type-only default imports combined with typeof for component type annotations (e.g., `import type SolidQueryDevtoolsComp from './devtools'` followed by `typeof SolidQueryDevtoolsComp`). This pattern is consistently used across index.tsx and production.tsx files, and the maintainers prefer consistency over changing this approach.
📚 Learning: 2025-11-22T09:06:05.219Z
Learnt from: sukvvon
Repo: TanStack/query PR: 9892
File: packages/solid-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx:331-335
Timestamp: 2025-11-22T09:06:05.219Z
Learning: In TanStack/query test files, when a queryFn contains side effects (e.g., setting flags for test verification), prefer async/await syntax for clarity; when there are no side effects, prefer the .then() pattern for conciseness.

Applied to files:

  • packages/vue-query/src/__tests__/queryOptions.test-d.ts
📚 Learning: 2025-11-02T22:52:33.071Z
Learnt from: DogPawHat
Repo: TanStack/query PR: 9835
File: packages/query-core/src/__tests__/queryClient.test-d.tsx:242-256
Timestamp: 2025-11-02T22:52:33.071Z
Learning: In the TanStack Query codebase, the new `query` and `infiniteQuery` methods support the `select` option for data transformation, while the legacy `fetchQuery` and `fetchInfiniteQuery` methods do not support `select` and should reject it at the type level.

Applied to files:

  • packages/vue-query/src/__tests__/queryOptions.test-d.ts
  • packages/vue-query/src/queryOptions.ts
📚 Learning: 2025-08-19T03:18:18.303Z
Learnt from: oscartbeaumont
Repo: TanStack/query PR: 9564
File: packages/solid-query-devtools/src/production.tsx:2-3
Timestamp: 2025-08-19T03:18:18.303Z
Learning: In the solid-query-devtools package, the codebase uses a pattern of type-only default imports combined with typeof for component type annotations (e.g., `import type SolidQueryDevtoolsComp from './devtools'` followed by `typeof SolidQueryDevtoolsComp`). This pattern is consistently used across index.tsx and production.tsx files, and the maintainers prefer consistency over changing this approach.

Applied to files:

  • packages/vue-query/src/queryOptions.ts
🧬 Code graph analysis (1)
packages/vue-query/src/__tests__/queryOptions.test-d.ts (1)
packages/vue-query/src/queryOptions.ts (1)
  • queryOptions (78-80)
🔇 Additional comments (3)
packages/vue-query/src/__tests__/queryOptions.test-d.ts (1)

9-22: LGTM! Well-structured type test for issue #7892.

The test correctly verifies that:

  • queryFn and staleTime are accessible with proper types including undefined (since they're optional)
  • queryKey uses toMatchTypeOf appropriately since the actual type is DataTag<...> which extends readonly unknown[]
packages/vue-query/src/queryOptions.ts (2)

11-31: LGTM! Clean type definition that directly addresses the core issue.

Using QueryObserverOptions directly (rather than wrapped in MaybeRef) ensures that properties like queryFn, staleTime, etc. are accessible on the returned options object. The JSDoc comment clearly documents the design intent.


33-54: LGTM! Correct distinction from DefinedInitialDataOptions.

The initialData field properly allows:

  • Omission (optional with ?)
  • Explicit undefined
  • A function that may return undefined (InitialDataFunction)
  • A direct non-undefined value

This ensures the overload resolution correctly routes to DefinedInitialDataOptions when initialData is guaranteed to be defined.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[vue-query] Type error: queryOptions return type only contains the queryKey and initialData properties

1 participant