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
11 changes: 11 additions & 0 deletions .changeset/fix-vue-query-options-type.md
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 10 additions & 0 deletions packages/vue-query/src/__tests__/queryOptions.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,14 @@ describe('queryOptions', () => {

expectTypeOf(data).toEqualTypeOf<number>()
})

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()
})
})
16 changes: 14 additions & 2 deletions packages/vue-query/src/queryOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> = Exclude<T, Ref<any> | ComputedRef<any>>

export function queryOptions<
TQueryFnData = unknown,
Expand All @@ -11,7 +19,9 @@ export function queryOptions<
TQueryKey extends QueryKey = QueryKey,
>(
options: DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
): DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
): PlainQueryOptions<
DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>
> & {
queryKey: DataTag<TQueryKey, TQueryFnData, TError>
}

Expand All @@ -22,7 +32,9 @@ export function queryOptions<
TQueryKey extends QueryKey = QueryKey,
>(
options: UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
): UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey> & {
): PlainQueryOptions<
UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>
> & {
queryKey: DataTag<TQueryKey, TQueryFnData, TError>
}

Expand Down
18 changes: 18 additions & 0 deletions packages/vue-query/src/useQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useQueryClient } from './useQueryClient'
import { cloneDeepUnref } from './utils'
import type { Ref } from 'vue-demi'
import type {
DataTag,
DefaultError,
DefinedQueryObserverResult,
QueriesObserverOptions,
Expand Down Expand Up @@ -45,6 +46,10 @@ type GetUseQueryOptionsForUseQueries<T> =
// Part 1: if UseQueryOptions are already being sent through, then just return T
T extends UseQueryOptions
? DeepUnwrapRef<T>
: // Part 1b: handle plain query options returned by queryOptions()
// (ExtractPlainType removes MaybeRef branches, so they need DeepUnwrapRef too)
T extends { queryKey: DataTag<any, any, any> }
? DeepUnwrapRef<T>
: // Part 2: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
T extends {
queryFnData: infer TQueryFnData
Expand Down Expand Up @@ -123,6 +128,19 @@ type GetUseQueryResult<T> =
undefined extends TData ? TQueryFnData : TData,
unknown extends TError ? DefaultError : TError
>
: // Part 1b: handle plain query options from queryOptions()
T extends { queryKey: DataTag<any, infer TQueryFnData, infer TError> }
? 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<T, TData, TError>
Expand Down