From db92891ec867c2e8cd3029dc68a95d51456a8b5e 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 617721bcb49da8336d9308dadd87e97a6b9c1bb8 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 dee80285ae227278eb24e49b29a715ea9949614b 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 449ab13b16ce2be739ed4d6c1cd9dfdea9fef087 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', () => {