diff --git a/.changeset/calm-vue-query-options.md b/.changeset/calm-vue-query-options.md new file mode 100644 index 0000000000..331c4338c6 --- /dev/null +++ b/.changeset/calm-vue-query-options.md @@ -0,0 +1,8 @@ +--- +'@tanstack/query-core': patch +'@tanstack/vue-query': patch +--- + +Export query option declaration helper types for portable Vue queryOptions factories. +The previous `useQuery`-specific initial-data helper types remain available as +`UndefinedInitialUseQueryOptions` and `DefinedInitialUseQueryOptions`. diff --git a/packages/query-core/src/index.ts b/packages/query-core/src/index.ts index a4267aabc9..07b8916a3e 100644 --- a/packages/query-core/src/index.ts +++ b/packages/query-core/src/index.ts @@ -20,6 +20,8 @@ export type { QueryCacheNotifyEvent } from './queryCache' export { QueryClient } from './queryClient' export { QueryObserver } from './queryObserver' export { CancelledError, isCancelledError } from './retryer' +export type { RetryDelayValue, RetryValue } from './retryer' +export type { QueryBehavior } from './query' export { timeoutManager, type ManagedTimerId, diff --git a/packages/vue-query/src/__tests__/queryOptions.test-d.ts b/packages/vue-query/src/__tests__/queryOptions.test-d.ts index a3e8c6d0d4..64c4f32f38 100644 --- a/packages/vue-query/src/__tests__/queryOptions.test-d.ts +++ b/packages/vue-query/src/__tests__/queryOptions.test-d.ts @@ -5,6 +5,9 @@ import { queryKey } from '@tanstack/query-test-utils' import { QueryClient } from '../queryClient' import { queryOptions } from '../queryOptions' import { useQuery } from '../useQuery' +import type { ComputedRef, Ref } from 'vue-demi' +import type { DataTag } from '@tanstack/query-core' +import type { QueryOptionsDataTag, UndefinedInitialQueryOptions } from '..' describe('queryOptions', () => { it('should not allow excess properties', () => { @@ -308,7 +311,11 @@ describe('queryOptions', () => { queryFn: () => Promise.resolve({ id: '1' }), }) - expectTypeOf(options.queryKey).not.toBeUndefined() + expectTypeOf(options.queryKey).toEqualTypeOf< + ComputedRef< + DataTag + > + >() }) it('should allow ref as queryKey', () => { @@ -319,7 +326,9 @@ describe('queryOptions', () => { queryFn: () => Promise.resolve({ id: '1' }), }) - expectTypeOf(options.queryKey).not.toBeUndefined() + expectTypeOf(options.queryKey).toEqualTypeOf< + Ref> + >() }) it('should allow getter function as queryKey', () => { @@ -330,6 +339,46 @@ describe('queryOptions', () => { queryFn: () => Promise.resolve({ id: '1' }), }) - expectTypeOf(options.queryKey).not.toBeUndefined() + expectTypeOf(options.queryKey).toEqualTypeOf< + () => DataTag + >() + }) + + it('should allow public queryOptions types to be used in declaration emit', () => { + type Todo = { + id: number + name: string + } + + type TodoOptions = UndefinedInitialQueryOptions< + Todo, + Error, + Todo, + readonly ['todo'] + > + + function todoOptions(): TodoOptions { + return queryOptions({ + queryKey: ['todo'] as const, + queryFn: () => Promise.resolve({ id: 1, name: 'one' }), + }) + } + + expectTypeOf( + queryOptions({ + queryKey: ['todo'] as const, + queryFn: (): Promise => Promise.resolve({ id: 1, name: 'one' }), + }), + ).toEqualTypeOf< + QueryOptionsDataTag + >() + + queryOptions({ + ...todoOptions(), + select: (data) => { + expectTypeOf(data).toEqualTypeOf() + return data.name + }, + }) }) }) diff --git a/packages/vue-query/src/index.ts b/packages/vue-query/src/index.ts index 36c616b12a..339afc49f9 100644 --- a/packages/vue-query/src/index.ts +++ b/packages/vue-query/src/index.ts @@ -6,7 +6,12 @@ export { VueQueryPlugin } from './vueQueryPlugin' export { QueryClient } from './queryClient' export { QueryCache } from './queryCache' export { queryOptions } from './queryOptions' -export { type QueryOptions } from './queryOptions' +export type { + DefinedInitialQueryOptions, + QueryOptions, + QueryOptionsDataTag, + UndefinedInitialQueryOptions, +} from './queryOptions' export { infiniteQueryOptions } from './infiniteQueryOptions' export type { DefinedInitialDataInfiniteOptions, @@ -30,15 +35,15 @@ export type { UseQueryOptions, UseQueryReturnType, UseQueryDefinedReturnType, - UndefinedInitialQueryOptions, - DefinedInitialQueryOptions, + UndefinedInitialQueryOptions as UndefinedInitialUseQueryOptions, + DefinedInitialQueryOptions as DefinedInitialUseQueryOptions, } from './useQuery' export type { UseInfiniteQueryOptions, UseInfiniteQueryReturnType, } from './useInfiniteQuery' export type { UseMutationOptions, UseMutationReturnType } from './useMutation' -export type { MutationOptions } from './types' +export type { MaybeRefOrGetter, MutationOptions, ShallowOption } from './types' export type { UseQueriesOptions, UseQueriesResults } from './useQueries' export type { MutationFilters, MutationStateOptions } from './useMutationState' export type { QueryFilters } from './useIsFetching' diff --git a/packages/vue-query/src/queryOptions.ts b/packages/vue-query/src/queryOptions.ts index 37e7f22b4f..44c53d6657 100644 --- a/packages/vue-query/src/queryOptions.ts +++ b/packages/vue-query/src/queryOptions.ts @@ -1,4 +1,5 @@ import type { DeepUnwrapRef, MaybeRefOrGetter, ShallowOption } from './types' +import type { ComputedRef, Ref } from 'vue-demi' import type { DataTag, DefaultError, @@ -65,64 +66,108 @@ export type DefinedInitialQueryOptions< | (() => NonUndefinedGuard) } +export type QueryOptionsDataTag = + Omit & { + queryKey: TaggedQueryKey< + TOptions, + TQueryFnData, + TError, + TQueryKey + > + } + +type TaggedQueryKey = + TOptions extends { queryKey: infer TQueryKeyOption } + ? TQueryKeyOption extends () => infer TQueryKeyFromGetter + ? () => DataTag + : TQueryKeyOption extends ComputedRef + ? ComputedRef> + : TQueryKeyOption extends Ref + ? Ref> + : TQueryKeyOption extends QueryKey + ? DataTag + : DataTag + : DataTag + export function queryOptions< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, + TOptions extends DefinedInitialQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey + > = DefinedInitialQueryOptions, >( - options: DefinedInitialQueryOptions, -): DefinedInitialQueryOptions & { - queryKey: DataTag -} + options: TOptions, +): QueryOptionsDataTag< + TOptions, + TQueryFnData, + TError, + TQueryKey +> export function queryOptions< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, ->( - options: () => DefinedInitialQueryOptions< + TOptions extends DefinedInitialQueryOptions< TQueryFnData, TError, TData, TQueryKey - >, -): () => DefinedInitialQueryOptions & { - queryKey: DataTag -} + > = DefinedInitialQueryOptions, +>( + options: () => TOptions, +): () => QueryOptionsDataTag< + TOptions, + TQueryFnData, + TError, + TQueryKey +> export function queryOptions< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, + TOptions extends UndefinedInitialQueryOptions< + TQueryFnData, + TError, + TData, + TQueryKey + > = UndefinedInitialQueryOptions, >( - options: UndefinedInitialQueryOptions, -): UndefinedInitialQueryOptions & { - queryKey: DataTag -} + options: TOptions, +): QueryOptionsDataTag< + TOptions, + TQueryFnData, + TError, + TQueryKey +> export function queryOptions< TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey, ->( - options: () => UndefinedInitialQueryOptions< + TOptions extends UndefinedInitialQueryOptions< TQueryFnData, TError, TData, TQueryKey - >, -): () => UndefinedInitialQueryOptions< + > = UndefinedInitialQueryOptions, +>( + options: () => TOptions, +): () => QueryOptionsDataTag< + TOptions, TQueryFnData, TError, - TData, TQueryKey -> & { - queryKey: DataTag -} +> export function queryOptions(options: unknown) { return options