Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/vue-query-fetch-query-getter-options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tanstack/vue-query": patch
---

Unwrap getter function options passed to `queryClient.fetchQuery`.
14 changes: 14 additions & 0 deletions packages/vue-query/src/__tests__/queryClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,20 @@ describe('QueryCache', () => {
queryKey: queryKeyUnref,
})
})

it('should unwrap getter function options', () => {
const queryClient = new QueryClient()

queryClient.fetchQuery(() => ({
queryKey: queryKeyRef,
queryFn: fn,
}))

expect(QueryClientOrigin.prototype.fetchQuery).toHaveBeenCalledWith({
queryKey: queryKeyUnref,
queryFn: fn,
})
})
})

describe('prefetchQuery', () => {
Expand Down
12 changes: 10 additions & 2 deletions packages/vue-query/src/queryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ import type {
Updater,
} from '@tanstack/query-core'

type MaybeRefDeepOrGetter<T> = MaybeRefDeep<T> | (() => T)

function cloneDeepUnrefOrGet<T>(value: MaybeRefDeepOrGetter<T>): T {
const unwrapped = typeof value === 'function' ? (value as () => T)() : value

return cloneDeepUnref(unwrapped as MaybeRefDeep<T>)
Comment on lines +36 to +41

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

# Map relevant files and locate the types/overloads/test cases.
git ls-files packages/vue-query/src/queryClient.ts packages/vue-query/src | sed -n '1,120p'
printf '\n--- outline queryClient.ts ---\n'
ast-grep outline packages/vue-query/src/queryClient.ts --view expanded || true
printf '\n--- search for MaybeRefDeepOrGetter and getter overloads ---\n'
rg -n "MaybeRefDeepOrGetter|cloneDeepUnrefOrGet|FetchQueryOptions|MaybeRefDeep<FetchQueryOptions|\\(\\) =>" packages/vue-query/src packages/vue-query/test -S || true
printf '\n--- find query getter-related tests ---\n'
rg -n "queryKeyRef|getter|deep ref|MaybeRefDeep" packages/vue-query -S || true

Repository: TanStack/query

Length of output: 50371


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the relevant portion of queryClient.ts with line numbers.
sed -n '1,180p' packages/vue-query/src/queryClient.ts | cat -n

Repository: TanStack/query

Length of output: 6963


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect package typings and tests around the Vue Query client helpers.
find packages/vue-query -maxdepth 3 -type f | sort | sed -n '1,200p'

Repository: TanStack/query

Length of output: 3128


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' packages/vue-query/src/queryClient.ts | cat -n

Repository: TanStack/query

Length of output: 8707


🌐 Web query:

packages/vue-query/src/queryClient.ts MaybeRefDeepOrGetter FetchQueryOptions vue query getter deep refs

πŸ’‘ Result:

In TanStack Vue Query, MaybeRefDeepOrGetter is a type utility introduced to support both MaybeRef (Vue refs) and getter functions (() => T) within query options [1]. This allows for more flexible, reactive configurations that can handle complex, nested structures [1]. ### Core Concepts * MaybeRefDeep: Recursively transforms properties of type T into MaybeRef<T>, allowing deep reactivity where individual properties of an options object can be Vue refs [2]. * MaybeRefOrGetter: A union type (MaybeRef<T> | (() => T)) that allows passing either a static value, a Vue ref, or a getter function [2]. * MaybeRefDeepOrGetter: Extends the concept to handle deeply reactive objects while also permitting the entire object (or specific parts of it) to be returned by a getter function [1]. ### Technical Context in queryClient.ts In packages/vue-query/src/queryClient.ts, methods like fetchQuery and prefetchQuery utilize these type utilities to normalize incoming options [3][4]. Specifically, these methods apply cloneDeepUnref to the options object before passing them to the underlying query-core implementation [3][4]. cloneDeepUnref is a utility defined in packages/vue-query/src/utils.ts that performs several key tasks [5]: 1. Deep Unwrapping: It recursively traverses the options object to unwrap Ref values [5]. 2. Getter Resolution: It can be configured (by setting unrefGetters to true) to execute getter functions, allowing it to resolve reactive dependencies even when they are wrapped in functions rather than just refs [5]. 3. Integration: This mechanism bridges the gap between Vue's reactive system and the imperative, static-options-based nature of the core TanStack Query library [3][5]. ### Recent Developments Recent PRs and issues indicate ongoing refinements to these type utilities to ensure that getters and plain properties are handled correctly across all query methods, such as ensureQueryData and fetchQuery [6][7]. The goal of these changes is to maintain strict TypeScript compatibility while providing a seamless developer experience that mirrors how useQuery handles reactive options [6][1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the exact helper and overload area in the source file.
nl -ba packages/vue-query/src/queryClient.ts | sed -n '30,70p;290,320p'

Repository: TanStack/query

Length of output: 192


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the fetchQuery/prefetchQuery typings and the relevant d.ts tests.
sed -n '260,360p' packages/vue-query/src/queryClient.ts | cat -n
printf '\n--- queryClient.test-d.ts ---\n'
sed -n '1,220p' packages/vue-query/src/__tests__/queryClient.test-d.ts | cat -n

Repository: TanStack/query

Length of output: 9424


Allow deep refs in fetchQuery getters. cloneDeepUnrefOrGet() unwraps getter results, but the fetchQuery overload still types the getter branch as () => FetchQueryOptions<...>. That rejects getters returning ref-bearing options even though runtime accepts them. Change it to () => MaybeRefDeep<FetchQueryOptions<...>> so the type surface matches behavior.

πŸ€– 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/queryClient.ts` around lines 36 - 41, Update the
fetchQuery overload’s getter branch to accept () =>
MaybeRefDeep<FetchQueryOptions<...>> instead of only () =>
FetchQueryOptions<...>, matching cloneDeepUnrefOrGet runtime support for
ref-bearing options while preserving the existing non-getter overload behavior.

}

export class QueryClient extends QC {
constructor(config: QueryClientConfig = {}) {
const vueQueryConfig = {
Expand Down Expand Up @@ -301,11 +309,11 @@ export class QueryClient extends QC {
TQueryKey extends QueryKey = QueryKey,
TPageParam = never,
>(
options: MaybeRefDeep<
options: MaybeRefDeepOrGetter<
FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>
>,
): Promise<TData> {
return super.fetchQuery(cloneDeepUnref(options))
return super.fetchQuery(cloneDeepUnrefOrGet(options))
}

prefetchQuery<
Expand Down