diff --git a/packages/clients/tanstack-query/src/react.ts b/packages/clients/tanstack-query/src/react.ts index e84aa7e09..a62421de1 100644 --- a/packages/clients/tanstack-query/src/react.ts +++ b/packages/clients/tanstack-query/src/react.ts @@ -119,15 +119,15 @@ export type ModelSuspenseQueryResult = UseSuspenseQueryResult = Omit< - UseInfiniteQueryOptions>, +export type ModelInfiniteQueryOptions = Omit< + UseInfiniteQueryOptions, QueryKey, TPageParam>, 'queryKey' | 'initialPageParam' >; export type ModelInfiniteQueryResult = UseInfiniteQueryResult & { queryKey: QueryKey }; -export type ModelSuspenseInfiniteQueryOptions = Omit< - UseSuspenseInfiniteQueryOptions>, +export type ModelSuspenseInfiniteQueryOptions = Omit< + UseSuspenseInfiniteQueryOptions, QueryKey, TPageParam>, 'queryKey' | 'initialPageParam' >; @@ -263,15 +263,15 @@ export type ModelQueryHooks< options?: ModelSuspenseQueryOptions[]>, ): ModelSuspenseQueryResult[]>; - useInfiniteFindMany>( + useInfiniteFindMany, TPageParam = unknown>( args?: SelectSubset>, - options?: ModelInfiniteQueryOptions[]>, - ): ModelInfiniteQueryResult[]>>; + options?: ModelInfiniteQueryOptions[], TPageParam>, + ): ModelInfiniteQueryResult[], TPageParam>>; - useSuspenseInfiniteFindMany>( + useSuspenseInfiniteFindMany, TPageParam = unknown>( args?: SelectSubset>, - options?: ModelSuspenseInfiniteQueryOptions[]>, - ): ModelSuspenseInfiniteQueryResult[]>>; + options?: ModelSuspenseInfiniteQueryOptions[], TPageParam>, + ): ModelSuspenseInfiniteQueryResult[], TPageParam>>; useCreate>( options?: ModelMutationOptions, T>, @@ -592,14 +592,14 @@ export function useInternalSuspenseQuery( }; } -export function useInternalInfiniteQuery( +export function useInternalInfiniteQuery( _schema: SchemaDef, model: string, operation: string, args: unknown, options: | (Omit< - UseInfiniteQueryOptions>, + UseInfiniteQueryOptions, QueryKey, TPageParam>, 'queryKey' | 'initialPageParam' > & QueryContext) @@ -615,19 +615,19 @@ export function useInternalInfiniteQuery( queryFn: ({ pageParam, signal }) => { return fetcher(makeUrl(endpoint, model, operation, pageParam ?? args), { signal }, fetch); }, - initialPageParam: args, + initialPageParam: args as TPageParam, ...options, }), }; } -export function useInternalSuspenseInfiniteQuery( +export function useInternalSuspenseInfiniteQuery( _schema: SchemaDef, model: string, operation: string, args: unknown, options: Omit< - UseSuspenseInfiniteQueryOptions> & QueryContext, + UseSuspenseInfiniteQueryOptions, QueryKey, TPageParam> & QueryContext, 'queryKey' | 'initialPageParam' >, ) { @@ -640,7 +640,7 @@ export function useInternalSuspenseInfiniteQuery( queryFn: ({ pageParam, signal }) => { return fetcher(makeUrl(endpoint, model, operation, pageParam ?? args), { signal }, fetch); }, - initialPageParam: args, + initialPageParam: args as TPageParam, ...options, }), }; diff --git a/packages/clients/tanstack-query/src/svelte/index.svelte.ts b/packages/clients/tanstack-query/src/svelte/index.svelte.ts index 9ddfe40e2..639cf2969 100644 --- a/packages/clients/tanstack-query/src/svelte/index.svelte.ts +++ b/packages/clients/tanstack-query/src/svelte/index.svelte.ts @@ -125,8 +125,8 @@ export type ModelQueryOptions = Omit, 'qu export type ModelQueryResult = CreateQueryResult, DefaultError> & { queryKey: QueryKey }; -export type ModelInfiniteQueryOptions = Omit< - CreateInfiniteQueryOptions>, +export type ModelInfiniteQueryOptions = Omit< + CreateInfiniteQueryOptions, QueryKey, TPageParam>, 'queryKey' | 'initialPageParam' > & QueryContext; @@ -147,7 +147,10 @@ export type ModelMutationModelResult< Array extends boolean = false, Options extends QueryOptions = QueryOptions, ExtResult extends ExtResultBase = {}, -> = Omit, TArgs>, 'mutateAsync'> & { +> = Omit< + ModelMutationResult, TArgs>, + 'mutateAsync' +> & { mutateAsync( args: T, options?: ModelMutationOptions, T>, @@ -159,7 +162,12 @@ export type ClientHooks< Options extends QueryOptions = QueryOptions, ExtResult extends ExtResultBase = {}, > = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks< + Schema, + Model, + Options, + ExtResult + >; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -238,10 +246,14 @@ export type ModelQueryHooks< options?: Accessor[]>>, ): ModelQueryResult[]>; - useInfiniteFindMany>( + useInfiniteFindMany, TPageParam = unknown>( args?: Accessor>>, - options?: Accessor[]>>, - ): ModelInfiniteQueryResult[]>>; + options?: Accessor< + ModelInfiniteQueryOptions[], TPageParam> + >, + ): ModelInfiniteQueryResult< + InfiniteData[], TPageParam> + >; useCreate>( options?: Accessor, T>>, @@ -310,23 +322,20 @@ export type ModelQueryHooks< * const client = useClientQueries(schema) * ``` */ -export function useClientQueries< - SchemaOrClient extends SchemaDef | ClientContract, ->( +export function useClientQueries>( schema: InferSchema, options?: Accessor, -): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { - const result = Object.keys(schema.models).reduce( - (acc, model) => { - (acc as any)[lowerCaseFirst(model)] = useModelQueries( - schema as any, - model as any, - options, - ); - return acc; - }, - {} as any, - ); +): ClientHooks< + InferSchema, + InferOptions>, + InferExtResult extends ExtResultBase> + ? InferExtResult + : {} +> { + const result = Object.keys(schema.models).reduce((acc, model) => { + (acc as any)[lowerCaseFirst(model)] = useModelQueries(schema as any, model as any, options); + return acc; + }, {} as any); const procedures = (schema as any).procedures as Record | undefined; if (procedures) { @@ -376,7 +385,11 @@ export function useModelQueries< Model extends GetModels, Options extends QueryOptions, ExtResult extends ExtResultBase = {}, ->(schema: Schema, model: Model, rootOptions?: Accessor): ModelQueryHooks { +>( + schema: Schema, + model: Model, + rootOptions?: Accessor, +): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -487,14 +500,20 @@ export function useInternalQuery( return createQueryResult(query, queryKey); } -export function useInternalInfiniteQuery( +export function useInternalInfiniteQuery( _schema: SchemaDef, model: string, operation: string, - args: Accessor, + args?: Accessor, options?: Accessor< Omit< - CreateInfiniteQueryOptions>, + CreateInfiniteQueryOptions< + TQueryFnData, + DefaultError, + InfiniteData, + QueryKey, + TPageParam + >, 'queryKey' | 'initialPageParam' > & QueryContext @@ -502,21 +521,37 @@ export function useInternalInfiniteQuery( ) { const { endpoint, fetch } = useFetchOptions(options); - const queryKey = $derived(getQueryKey(model, operation, args(), { infinite: true, optimisticUpdate: false })); + const queryKey = $derived(getQueryKey(model, operation, args?.(), { infinite: true, optimisticUpdate: false })); const finalOptions = () => { - const queryFn: QueryFunction = ({ pageParam, signal }) => - fetcher(makeUrl(endpoint, model, operation, pageParam ?? args()), { signal }, fetch); + const queryFn: QueryFunction = ({ pageParam, signal }) => + fetcher(makeUrl(endpoint, model, operation, pageParam ?? args?.()), { signal }, fetch); const optionsValue = options?.() ?? { getNextPageParam: () => undefined }; return { queryKey, queryFn, - initialPageParam: args(), + initialPageParam: args?.() as TPageParam, ...optionsValue, }; }; - const query = createInfiniteQuery>(finalOptions); + const query = createInfiniteQuery< + TQueryFnData, + DefaultError, + InfiniteData, + QueryKey, + TPageParam + >( + finalOptions as unknown as Accessor< + CreateInfiniteQueryOptions< + TQueryFnData, + DefaultError, + InfiniteData, + QueryKey, + TPageParam + > + >, + ); // svelte-ignore state_referenced_locally return createQueryResult(query, queryKey); } diff --git a/packages/clients/tanstack-query/src/vue.ts b/packages/clients/tanstack-query/src/vue.ts index 4b0e8a682..32ab6e656 100644 --- a/packages/clients/tanstack-query/src/vue.ts +++ b/packages/clients/tanstack-query/src/vue.ts @@ -118,8 +118,11 @@ export type ModelQueryOptions = MaybeRefOrGetter< export type ModelQueryResult = UseQueryReturnType, DefaultError> & { queryKey: Ref }; -export type ModelInfiniteQueryOptions = MaybeRefOrGetter< - Omit>>, 'queryKey' | 'initialPageParam'> & +export type ModelInfiniteQueryOptions = MaybeRefOrGetter< + Omit< + UnwrapRef, QueryKey, TPageParam>>, + 'queryKey' | 'initialPageParam' + > & QueryContext >; @@ -241,10 +244,10 @@ export type ModelQueryHooks< options?: MaybeRefOrGetter[]>>, ): ModelQueryResult[]>; - useInfiniteFindMany>( + useInfiniteFindMany, TPageParam = unknown>( args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter[]>>, - ): ModelInfiniteQueryResult[]>>; + options?: MaybeRefOrGetter[], TPageParam>>, + ): ModelInfiniteQueryResult[], TPageParam>>; useCreate>( options?: MaybeRefOrGetter, T>>, @@ -510,14 +513,16 @@ export function useInternalQuery( return { queryKey, ...useQuery(finalOptions) }; } -export function useInternalInfiniteQuery( +export function useInternalInfiniteQuery( _schema: SchemaDef, model: string, operation: string, args: MaybeRefOrGetter, options: MaybeRefOrGetter< | (Omit< - UnwrapRef>>, + UnwrapRef< + UseInfiniteQueryOptions, QueryKey, TPageParam> + >, 'queryKey' | 'initialPageParam' > & QueryContext) @@ -543,7 +548,7 @@ export function useInternalInfiniteQuery( const reqUrl = makeUrl(endpoint, model, operation, argsValue); return fetcher(reqUrl, { signal }, fetch); }, - initialPageParam: toValue(argsValue), + initialPageParam: toValue(argsValue) as TPageParam, ...toValue(options), }; }); diff --git a/packages/clients/tanstack-query/test/react-typing.test-d.ts b/packages/clients/tanstack-query/test/react-typing.test-d.ts index 3dbcd8446..876336c5e 100644 --- a/packages/clients/tanstack-query/test/react-typing.test-d.ts +++ b/packages/clients/tanstack-query/test/react-typing.test-d.ts @@ -37,6 +37,16 @@ describe('React client typing test', () => { }, ).data?.pages[1]?.[0]?.email, ); + + // TPageParam should be inferred from getNextPageParam, not typed as unknown + const infiniteResult = client.user.useInfiniteFindMany( + {}, + { + getNextPageParam: (_lastPage, _allPages, lastPageParam: { cursor: string }) => lastPageParam, + }, + ); + check(infiniteResult.data?.pageParams[0]?.cursor); + // @ts-expect-error check(client.user.useInfiniteFindMany().data?.pages[0]?.[0]?.$optimistic); diff --git a/packages/clients/tanstack-query/test/svelte-typing-test.ts b/packages/clients/tanstack-query/test/svelte-typing-test.ts index eda2add95..492b086a1 100644 --- a/packages/clients/tanstack-query/test/svelte-typing-test.ts +++ b/packages/clients/tanstack-query/test/svelte-typing-test.ts @@ -43,6 +43,15 @@ check( // @ts-expect-error check(client.user.useInfiniteFindMany().data?.pages[0]?.[0]?.$optimistic); +// TPageParam should be inferred from getNextPageParam, not typed as unknown +const infiniteResult = client.user.useInfiniteFindMany( + () => ({}), + () => ({ + getNextPageParam: (_lastPage: unknown, _allPages: unknown, lastPageParam: { cursor: string }) => lastPageParam, + }), +); +check(infiniteResult.data?.pageParams[0]?.cursor); + check(client.user.useCount().data?.toFixed(2)); check(client.user.useCount(() => ({ select: { email: true } })).data?.email.toFixed(2)); diff --git a/packages/clients/tanstack-query/test/vue-typing-test.ts b/packages/clients/tanstack-query/test/vue-typing-test.ts index 60099fb2f..fdd4f8541 100644 --- a/packages/clients/tanstack-query/test/vue-typing-test.ts +++ b/packages/clients/tanstack-query/test/vue-typing-test.ts @@ -38,6 +38,15 @@ check( // @ts-expect-error check(client.user.useInfiniteFindMany().data.value?.pages[0]?.[0]?.$optimistic); +// TPageParam should be inferred from getNextPageParam, not typed as unknown +const infiniteResult = client.user.useInfiniteFindMany( + {}, + { + getNextPageParam: (_lastPage: unknown, _allPages: unknown, lastPageParam: { cursor: string }) => lastPageParam, + }, +); +check(infiniteResult.data.value?.pageParams[0]?.cursor); + check(client.user.useCount().data.value?.toFixed(2)); check(client.user.useCount({ select: { email: true } }).data.value?.email.toFixed(2));