From cc06f3cc7da0e71767d6a980f7603be19617fedf Mon Sep 17 00:00:00 2001 From: Vedant Madane <6527493+VedantMadane@users.noreply.github.com> Date: Thu, 15 Jan 2026 09:54:06 +0530 Subject: [PATCH 1/4] fix(vue-query): expose queryFn and other properties on queryOptions return 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 #7892 Signed-off-by: Vedant Madane <6527493+VedantMadane@users.noreply.github.com> --- .../src/__tests__/queryOptions.test-d.ts | 15 +++++ packages/vue-query/src/queryOptions.ts | 65 ++++++++++++++++--- 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/packages/vue-query/src/__tests__/queryOptions.test-d.ts b/packages/vue-query/src/__tests__/queryOptions.test-d.ts index 65d49d945f..3514a97eec 100644 --- a/packages/vue-query/src/__tests__/queryOptions.test-d.ts +++ b/packages/vue-query/src/__tests__/queryOptions.test-d.ts @@ -6,6 +6,21 @@ import { queryOptions } from '../queryOptions' import { useQuery } from '../useQuery' describe('queryOptions', () => { + it('should expose queryFn and other properties on the returned options object', () => { + const options = queryOptions({ + queryKey: ['key'], + queryFn: () => Promise.resolve(5), + staleTime: 1000, + }) + + // These should be accessible without TS errors (issue #7892) + expectTypeOf(options.queryFn).toEqualTypeOf< + (() => Promise) | undefined + >() + expectTypeOf(options.staleTime).toEqualTypeOf() + expectTypeOf(options.queryKey).toMatchTypeOf() + }) + it('should not allow excess properties', () => { assertType( queryOptions({ diff --git a/packages/vue-query/src/queryOptions.ts b/packages/vue-query/src/queryOptions.ts index 4681080f8c..c5d91a0839 100644 --- a/packages/vue-query/src/queryOptions.ts +++ b/packages/vue-query/src/queryOptions.ts @@ -1,8 +1,57 @@ -import type { DataTag, DefaultError, QueryKey } from '@tanstack/query-core' import type { - DefinedInitialQueryOptions, - UndefinedInitialQueryOptions, -} from './useQuery' + DataTag, + DefaultError, + InitialDataFunction, + NonUndefinedGuard, + QueryKey, + QueryObserverOptions, +} from '@tanstack/query-core' +import type { DeepUnwrapRef, ShallowOption } from './types' + +/** + * Options for queryOptions with defined initial data. + * These are unwrapped types (not MaybeRef) so that properties like queryFn are directly accessible. + */ +export type DefinedInitialDataOptions< + TQueryFnData = unknown, + TError = DefaultError, + TData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey, +> = QueryObserverOptions< + TQueryFnData, + TError, + TData, + TQueryFnData, + DeepUnwrapRef +> & + ShallowOption & { + initialData: + | NonUndefinedGuard + | (() => NonUndefinedGuard) + } + +/** + * Options for queryOptions with undefined initial data. + * These are unwrapped types (not MaybeRef) so that properties like queryFn are directly accessible. + */ +export type UndefinedInitialDataOptions< + TQueryFnData = unknown, + TError = DefaultError, + TData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey, +> = QueryObserverOptions< + TQueryFnData, + TError, + TData, + TQueryFnData, + DeepUnwrapRef +> & + ShallowOption & { + initialData?: + | undefined + | InitialDataFunction> + | NonUndefinedGuard + } export function queryOptions< TQueryFnData = unknown, @@ -10,8 +59,8 @@ export function queryOptions< TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( - options: DefinedInitialQueryOptions, -): DefinedInitialQueryOptions & { + options: DefinedInitialDataOptions, +): DefinedInitialDataOptions & { queryKey: DataTag } @@ -21,8 +70,8 @@ export function queryOptions< TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, >( - options: UndefinedInitialQueryOptions, -): UndefinedInitialQueryOptions & { + options: UndefinedInitialDataOptions, +): UndefinedInitialDataOptions & { queryKey: DataTag } From 0f3faf4dd79ea3092e32ea0cfcd86101d261d07a Mon Sep 17 00:00:00 2001 From: Vedant Madane <6527493+VedantMadane@users.noreply.github.com> Date: Wed, 21 Jan 2026 15:04:19 +0530 Subject: [PATCH 2/4] Fix query options types in vue-query Expose queryFn and other properties on queryOptions return type. --- .changeset/fix-query-options-types-fix.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-query-options-types-fix.md diff --git a/.changeset/fix-query-options-types-fix.md b/.changeset/fix-query-options-types-fix.md new file mode 100644 index 0000000000..8a8b494d96 --- /dev/null +++ b/.changeset/fix-query-options-types-fix.md @@ -0,0 +1,5 @@ +--- +'@tanstack/vue-query': patch +--- + +fix(vue-query): expose queryFn and other properties on queryOptions return type From 382aca16c69a5d0fe1aab2d73795d0fb87e81905 Mon Sep 17 00:00:00 2001 From: Vedant Madane <6527493+VedantMadane@users.noreply.github.com> Date: Mon, 26 Jan 2026 15:42:36 +0530 Subject: [PATCH 3/4] fix: use intersection types for compatibility with useQuery - Replace QueryObserverOptions with intersection of existing types - Maintains compatibility with useQuery overloads - Uses UndefinedInitialQueryOptions & DefinedInitialQueryOptions as base - Explicitly exposes queryKey and queryFn properties - Update test to use toMatchTypeOf for intersection types --- .../src/__tests__/queryOptions.test-d.ts | 4 +- packages/vue-query/src/queryOptions.ts | 55 +++++++------------ 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/packages/vue-query/src/__tests__/queryOptions.test-d.ts b/packages/vue-query/src/__tests__/queryOptions.test-d.ts index 3514a97eec..34e540343e 100644 --- a/packages/vue-query/src/__tests__/queryOptions.test-d.ts +++ b/packages/vue-query/src/__tests__/queryOptions.test-d.ts @@ -14,10 +14,10 @@ describe('queryOptions', () => { }) // These should be accessible without TS errors (issue #7892) - expectTypeOf(options.queryFn).toEqualTypeOf< + expectTypeOf(options.queryFn).toMatchTypeOf< (() => Promise) | undefined >() - expectTypeOf(options.staleTime).toEqualTypeOf() + expectTypeOf(options.staleTime).toMatchTypeOf() expectTypeOf(options.queryKey).toMatchTypeOf() }) diff --git a/packages/vue-query/src/queryOptions.ts b/packages/vue-query/src/queryOptions.ts index c5d91a0839..343bdfbcc0 100644 --- a/packages/vue-query/src/queryOptions.ts +++ b/packages/vue-query/src/queryOptions.ts @@ -1,57 +1,42 @@ import type { DataTag, DefaultError, - InitialDataFunction, - NonUndefinedGuard, + QueryFunction, QueryKey, - QueryObserverOptions, } from '@tanstack/query-core' -import type { DeepUnwrapRef, ShallowOption } from './types' +import type { + DefinedInitialQueryOptions, + UndefinedInitialQueryOptions, +} from './useQuery' +import type { DeepUnwrapRef } from './types' /** - * Options for queryOptions with defined initial data. - * These are unwrapped types (not MaybeRef) so that properties like queryFn are directly accessible. + * Augmented version of UndefinedInitialQueryOptions that explicitly exposes + * queryFn and other properties for direct TypeScript access. */ -export type DefinedInitialDataOptions< +export type UndefinedInitialDataOptions< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, -> = QueryObserverOptions< - TQueryFnData, - TError, - TData, - TQueryFnData, - DeepUnwrapRef -> & - ShallowOption & { - initialData: - | NonUndefinedGuard - | (() => NonUndefinedGuard) - } +> = UndefinedInitialQueryOptions & { + queryKey: TQueryKey + queryFn?: QueryFunction> +} /** - * Options for queryOptions with undefined initial data. - * These are unwrapped types (not MaybeRef) so that properties like queryFn are directly accessible. + * Augmented version of DefinedInitialQueryOptions that explicitly exposes + * queryFn and other properties for direct TypeScript access. */ -export type UndefinedInitialDataOptions< +export type DefinedInitialDataOptions< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, -> = QueryObserverOptions< - TQueryFnData, - TError, - TData, - TQueryFnData, - DeepUnwrapRef -> & - ShallowOption & { - initialData?: - | undefined - | InitialDataFunction> - | NonUndefinedGuard - } +> = DefinedInitialQueryOptions & { + queryKey: TQueryKey + queryFn?: QueryFunction> +} export function queryOptions< TQueryFnData = unknown, From c790f780cc6fcff6b511b3b9264513e9c967efcb Mon Sep 17 00:00:00 2001 From: Vedant Madane <6527493+VedantMadane@users.noreply.github.com> Date: Mon, 26 Jan 2026 16:15:55 +0530 Subject: [PATCH 4/4] fix: use ReadonlyArray generic instead of readonly array syntax - Change readonly unknown[] to ReadonlyArray - Complies with project's ESLint config that disallows inline readonly syntax --- packages/vue-query/src/__tests__/queryOptions.test-d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vue-query/src/__tests__/queryOptions.test-d.ts b/packages/vue-query/src/__tests__/queryOptions.test-d.ts index 34e540343e..ce63a08a28 100644 --- a/packages/vue-query/src/__tests__/queryOptions.test-d.ts +++ b/packages/vue-query/src/__tests__/queryOptions.test-d.ts @@ -18,7 +18,7 @@ describe('queryOptions', () => { (() => Promise) | undefined >() expectTypeOf(options.staleTime).toMatchTypeOf() - expectTypeOf(options.queryKey).toMatchTypeOf() + expectTypeOf(options.queryKey).toMatchTypeOf>() }) it('should not allow excess properties', () => {