From 551270e782ad87a02105f24dfe29f3f012410775 Mon Sep 17 00:00:00 2001 From: Varun Chawla Date: Sun, 8 Feb 2026 13:03:53 -0800 Subject: [PATCH] fix(vue-query): fix queryOptions return type by removing MaybeRef branches The queryOptions return type was a MaybeRef union type (T | Ref | ComputedRef) intersected with { initialData?, queryKey }. TypeScript only shows properties common to all union members, so only queryKey and initialData were accessible via dot notation. Fix by using Exclude on the return type to remove the Ref and ComputedRef branches, since queryOptions always returns a plain object. Also update useQueries type inference to handle these plain types via DataTag-based matching. Fixes #7892 --- .changeset/fix-vue-query-options-type.md | 11 +++++++++++ .../src/__tests__/queryOptions.test-d.ts | 10 ++++++++++ packages/vue-query/src/queryOptions.ts | 16 ++++++++++++++-- packages/vue-query/src/useQueries.ts | 18 ++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 .changeset/fix-vue-query-options-type.md diff --git a/.changeset/fix-vue-query-options-type.md b/.changeset/fix-vue-query-options-type.md new file mode 100644 index 0000000000..13e821520b --- /dev/null +++ b/.changeset/fix-vue-query-options-type.md @@ -0,0 +1,11 @@ +--- +'@tanstack/vue-query': patch +--- + +fix(vue-query): fix queryOptions return type to expose all properties + +The `queryOptions` return type now correctly exposes all query option +properties (like `queryFn`, `staleTime`, etc.) for direct access, not +just `queryKey` and `initialData`. This is achieved by excluding the +`Ref` and `ComputedRef` branches from the `MaybeRef` union in the return +type, since `queryOptions` always returns a plain object. diff --git a/packages/vue-query/src/__tests__/queryOptions.test-d.ts b/packages/vue-query/src/__tests__/queryOptions.test-d.ts index 65d49d945f..a1edba838e 100644 --- a/packages/vue-query/src/__tests__/queryOptions.test-d.ts +++ b/packages/vue-query/src/__tests__/queryOptions.test-d.ts @@ -212,4 +212,14 @@ describe('queryOptions', () => { expectTypeOf(data).toEqualTypeOf() }) + + it('should allow accessing queryFn and other properties on the returned options object', () => { + const options = queryOptions({ + queryKey: ['groups'], + queryFn: () => Promise.resolve([]), + }) + + expectTypeOf(options.queryFn).not.toBeUndefined() + expectTypeOf(options.queryKey).not.toBeUndefined() + }) }) diff --git a/packages/vue-query/src/queryOptions.ts b/packages/vue-query/src/queryOptions.ts index 4681080f8c..ba053dd3cd 100644 --- a/packages/vue-query/src/queryOptions.ts +++ b/packages/vue-query/src/queryOptions.ts @@ -3,6 +3,14 @@ import type { DefinedInitialQueryOptions, UndefinedInitialQueryOptions, } from './useQuery' +import type { ComputedRef, Ref } from 'vue-demi' + +// Removes Ref and ComputedRef branches from a MaybeRef union type, +// leaving only the plain object type so all properties are directly +// accessible via dot notation. +// Fixes #7892: queryOptions return type only contains queryKey and +// initialData properties due to MaybeRef union narrowing. +type PlainQueryOptions = Exclude | ComputedRef> export function queryOptions< TQueryFnData = unknown, @@ -11,7 +19,9 @@ export function queryOptions< TQueryKey extends QueryKey = QueryKey, >( options: DefinedInitialQueryOptions, -): DefinedInitialQueryOptions & { +): PlainQueryOptions< + DefinedInitialQueryOptions +> & { queryKey: DataTag } @@ -22,7 +32,9 @@ export function queryOptions< TQueryKey extends QueryKey = QueryKey, >( options: UndefinedInitialQueryOptions, -): UndefinedInitialQueryOptions & { +): PlainQueryOptions< + UndefinedInitialQueryOptions +> & { queryKey: DataTag } diff --git a/packages/vue-query/src/useQueries.ts b/packages/vue-query/src/useQueries.ts index f290976a14..385b6720ff 100644 --- a/packages/vue-query/src/useQueries.ts +++ b/packages/vue-query/src/useQueries.ts @@ -14,6 +14,7 @@ import { useQueryClient } from './useQueryClient' import { cloneDeepUnref } from './utils' import type { Ref } from 'vue-demi' import type { + DataTag, DefaultError, DefinedQueryObserverResult, QueriesObserverOptions, @@ -45,6 +46,10 @@ type GetUseQueryOptionsForUseQueries = // Part 1: if UseQueryOptions are already being sent through, then just return T T extends UseQueryOptions ? DeepUnwrapRef + : // Part 1b: handle plain query options returned by queryOptions() + // (ExtractPlainType removes MaybeRef branches, so they need DeepUnwrapRef too) + T extends { queryKey: DataTag } + ? DeepUnwrapRef : // Part 2: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData } T extends { queryFnData: infer TQueryFnData @@ -123,6 +128,19 @@ type GetUseQueryResult = undefined extends TData ? TQueryFnData : TData, unknown extends TError ? DefaultError : TError > + : // Part 1b: handle plain query options from queryOptions() + T extends { queryKey: DataTag } + ? T extends { select?: (data: any) => infer TData } + ? GetDefinedOrUndefinedQueryResult< + T, + unknown extends TData ? TQueryFnData : TData, + unknown extends TError ? DefaultError : TError + > + : GetDefinedOrUndefinedQueryResult< + T, + TQueryFnData, + unknown extends TError ? DefaultError : TError + > : // Part 2: responsible for mapping explicit type parameter to function result, if object T extends { queryFnData: any; error?: infer TError; data: infer TData } ? GetDefinedOrUndefinedQueryResult