import type { DefinedInitialDataInfiniteOptions, DefinedUseInfiniteQueryResult, InfiniteData, SkipToken, UndefinedInitialDataInfiniteOptions, UseInfiniteQueryOptions, UseInfiniteQueryResult, UseSuspenseInfiniteQueryOptions, UseSuspenseInfiniteQueryResult, UseSuspenseQueryResult, } from '@tanstack/react-query'; import type { createTRPCClient, TRPCClientErrorLike } from '@trpc/client'; import type { AnyProcedure, AnyRootTypes, AnyRouter, inferAsyncIterableYield, inferProcedureInput, inferTransformedProcedureOutput, ProcedureType, ProtectedIntersection, RouterRecord, Simplify, } from '@trpc/server/unstable-core-do-not-import'; import { createFlatProxy } from '@trpc/server/unstable-core-do-not-import'; import * as React from 'react'; import type { TRPCUseQueries, TRPCUseSuspenseQueries, } from './internals/useQueries'; import type { CreateReactUtils, TRPCFetchInfiniteQueryOptions, TRPCFetchQueryOptions, } from './shared'; import { createReactDecoration, createReactQueryUtils } from './shared'; import type { CreateReactQueryHooks } from './shared/hooks/createHooksInternal'; import { createRootHooks } from './shared/hooks/createHooksInternal'; import type { DefinedUseTRPCQueryOptions, DefinedUseTRPCQueryResult, TRPCHookResult, TRPCProvider, TRPCSubscriptionResult, TRPCUseQueryBaseOptions, UseTRPCMutationOptions, UseTRPCMutationResult, UseTRPCQueryOptions, UseTRPCQueryResult, UseTRPCSubscriptionOptions, UseTRPCSuspenseQueryOptions, } from './shared/hooks/types'; import type { CreateTRPCReactOptions } from './shared/types'; type ResolverDef = { input: any; output: any; transformer: boolean; errorShape: any; }; /** * @internal */ export interface ProcedureUseQuery { ( input: TDef['input'] | SkipToken, opts: DefinedUseTRPCQueryOptions< TQueryFnData, TData, TRPCClientErrorLike<{ errorShape: TDef['errorShape']; transformer: TDef['transformer']; }>, TDef['output'] >, ): DefinedUseTRPCQueryResult< TData, TRPCClientErrorLike<{ errorShape: TDef['errorShape']; transformer: TDef['transformer']; }> >; ( input: TDef['input'] | SkipToken, opts?: UseTRPCQueryOptions< TQueryFnData, TData, TRPCClientErrorLike, TDef['output'] >, ): UseTRPCQueryResult>; } /** * @internal */ export type ProcedureUsePrefetchQuery = ( input: TDef['input'] | SkipToken, opts?: TRPCFetchQueryOptions>, ) => void; /** * @remark `void` is here due to https://github.com/trpc/trpc/pull/4374 */ type CursorInput = { cursor?: any; } | void; type ReservedInfiniteQueryKeys = 'cursor' | 'direction'; type InfiniteInput = | Omit | SkipToken; type inferCursorType = TInput extends { cursor?: any } ? TInput['cursor'] : unknown; type makeInfiniteQueryOptions = Omit< TOptions, 'queryKey' | 'initialPageParam' | 'queryFn' | 'queryHash' | 'queryHashFn' > & TRPCUseQueryBaseOptions & { initialCursor?: TCursor; }; type trpcInfiniteData = Simplify< InfiniteData> >; // references from react-query // 1st // declare function useInfiniteQuery< // TQueryFnData, // TError = DefaultError, // TData = InfiniteData, // TQueryKey extends QueryKey = QueryKey, // TPageParam = unknown, // >( // options: DefinedInitialDataInfiniteOptions< // TQueryFnData, // TError, // TData, // TQueryKey, // TPageParam // >, // queryClient?: QueryClient, // ): DefinedUseInfiniteQueryResult; // 2nd // declare function useInfiniteQuery< // TQueryFnData, // TError = DefaultError, // TData = InfiniteData, // TQueryKey extends QueryKey = QueryKey, // TPageParam = unknown, // >( // options: UndefinedInitialDataInfiniteOptions< // TQueryFnData, // TError, // TData, // TQueryKey, // TPageParam // >, // queryClient?: QueryClient, // ): UseInfiniteQueryResult; // 3rd // declare function useInfiniteQuery< // TQueryFnData, // TError = DefaultError, // TData = InfiniteData, // TQueryKey extends QueryKey = QueryKey, // TPageParam = unknown, // >( // options: UseInfiniteQueryOptions< // TQueryFnData, // TError, // TData, // TQueryFnData, // TQueryKey, // TPageParam // >, // queryClient?: QueryClient, // ): UseInfiniteQueryResult; export interface useTRPCInfiniteQuery { // 1st >( input: InfiniteInput, opts: makeInfiniteQueryOptions< inferCursorType, DefinedInitialDataInfiniteOptions< // TQueryFnData, TDef['output'], // TError, TRPCClientErrorLike, // TData, TData, // TQueryKey, any, // TPageParam inferCursorType > >, ): TRPCHookResult & DefinedUseInfiniteQueryResult>; // 2nd >( input: InfiniteInput, opts?: makeInfiniteQueryOptions< inferCursorType, UndefinedInitialDataInfiniteOptions< // TQueryFnData, TDef['output'], // TError, TRPCClientErrorLike, // TData, TData, // TQueryKey, any, // TPageParam inferCursorType > >, ): TRPCHookResult & UseInfiniteQueryResult>; // 3rd: >( input: InfiniteInput, opts?: makeInfiniteQueryOptions< inferCursorType, UseInfiniteQueryOptions< // TQueryFnData, TDef['output'], // TError, TRPCClientErrorLike, // TData, TData, // TQueryKey, any, // TPageParam inferCursorType > >, ): TRPCHookResult & UseInfiniteQueryResult>; } // references from react-query // declare function useSuspenseInfiniteQuery< // TQueryFnData, // TError = DefaultError, // TData = InfiniteData, // TQueryKey extends QueryKey = QueryKey, // TPageParam = unknown, // >( // options: UseSuspenseInfiniteQueryOptions< // TQueryFnData, // TError, // TData, // TQueryFnData, // TQueryKey, // TPageParam // >, // queryClient?: QueryClient, // ): UseSuspenseInfiniteQueryResult; export type useTRPCSuspenseInfiniteQuery = ( input: InfiniteInput, opts: makeInfiniteQueryOptions< inferCursorType, UseSuspenseInfiniteQueryOptions< // TQueryFnData, TDef['output'], // TError, TRPCClientErrorLike, // TData, trpcInfiniteData, // TQueryKey, any, // TPageParam inferCursorType > >, ) => [ trpcInfiniteData, TRPCHookResult & UseSuspenseInfiniteQueryResult< trpcInfiniteData, TRPCClientErrorLike >, ]; /** * @internal */ export type MaybeDecoratedInfiniteQuery = TDef['input'] extends CursorInput ? { /** * @see https://trpc.io/docs/v11/client/react/useInfiniteQuery */ useInfiniteQuery: useTRPCInfiniteQuery; /** * @see https://trpc.io/docs/client/react/suspense#usesuspenseinfinitequery */ useSuspenseInfiniteQuery: useTRPCSuspenseInfiniteQuery; usePrefetchInfiniteQuery: ( input: Omit | SkipToken, opts: TRPCFetchInfiniteQueryOptions< TDef['input'], TDef['output'], TRPCClientErrorLike >, ) => void; } : object; /** * @internal */ export type DecoratedQueryMethods = { /** * @see https://trpc.io/docs/v11/client/react/useQuery */ useQuery: ProcedureUseQuery; usePrefetchQuery: ProcedureUsePrefetchQuery; /** * @see https://trpc.io/docs/v11/client/react/suspense#usesuspensequery */ useSuspenseQuery: < TQueryFnData extends TDef['output'] = TDef['output'], TData = TQueryFnData, >( input: TDef['input'], opts?: UseTRPCSuspenseQueryOptions< TQueryFnData, TData, TRPCClientErrorLike >, ) => [ TData, UseSuspenseQueryResult> & TRPCHookResult, ]; }; /** * @internal */ export type DecoratedQuery = MaybeDecoratedInfiniteQuery & DecoratedQueryMethods; export type DecoratedMutation = { /** * @see https://trpc.io/docs/v11/client/react/useMutation */ useMutation: ( opts?: UseTRPCMutationOptions< TDef['input'], TRPCClientErrorLike, TDef['output'], TContext >, ) => UseTRPCMutationResult< TDef['output'], TRPCClientErrorLike, TDef['input'], TContext >; }; interface ProcedureUseSubscription { // Without skip token ( input: TDef['input'], opts?: UseTRPCSubscriptionOptions< inferAsyncIterableYield, TRPCClientErrorLike >, ): TRPCSubscriptionResult< inferAsyncIterableYield, TRPCClientErrorLike >; // With skip token ( input: TDef['input'] | SkipToken, opts?: Omit< UseTRPCSubscriptionOptions< inferAsyncIterableYield, TRPCClientErrorLike >, 'enabled' >, ): TRPCSubscriptionResult< inferAsyncIterableYield, TRPCClientErrorLike >; } /** * @internal */ export type DecorateProcedure< TType extends ProcedureType, TDef extends ResolverDef, > = TType extends 'query' ? DecoratedQuery : TType extends 'mutation' ? DecoratedMutation : TType extends 'subscription' ? { /** * @see https://trpc.io/docs/v11/subscriptions */ useSubscription: ProcedureUseSubscription; } : never; /** * @internal */ export type DecorateRouterRecord< TRoot extends AnyRootTypes, TRecord extends RouterRecord, > = { [TKey in keyof TRecord]: TRecord[TKey] extends infer $Value ? $Value extends AnyProcedure ? DecorateProcedure< $Value['_def']['type'], { input: inferProcedureInput<$Value>; output: inferTransformedProcedureOutput; transformer: TRoot['transformer']; errorShape: TRoot['errorShape']; } > : $Value extends RouterRecord ? DecorateRouterRecord : never : never; }; /** * @internal */ export type CreateTRPCReactBase = { /** * @deprecated renamed to `useUtils` and will be removed in a future tRPC version * * @see https://trpc.io/docs/v11/client/react/useUtils */ useContext(): CreateReactUtils; /** * @see https://trpc.io/docs/v11/client/react/useUtils */ useUtils(): CreateReactUtils; Provider: TRPCProvider; createClient: typeof createTRPCClient; useQueries: TRPCUseQueries; useSuspenseQueries: TRPCUseSuspenseQueries; }; export type CreateTRPCReact< TRouter extends AnyRouter, TSSRContext, > = ProtectedIntersection< CreateTRPCReactBase, DecorateRouterRecord< TRouter['_def']['_config']['$types'], TRouter['_def']['record'] > >; /** * @internal */ export function createHooksInternal< TRouter extends AnyRouter, TSSRContext = unknown, >(trpc: CreateReactQueryHooks) { type CreateHooksInternal = CreateTRPCReact; const proxy = createReactDecoration( trpc, ) as DecorateRouterRecord< TRouter['_def']['_config']['$types'], TRouter['_def']['record'] >; return createFlatProxy((key) => { if (key === 'useContext' || key === 'useUtils') { return () => { const context = trpc.useUtils(); // create a stable reference of the utils context return React.useMemo(() => { return (createReactQueryUtils as any)(context); }, [context]); }; } if (trpc.hasOwnProperty(key)) { return (trpc as any)[key]; } return proxy[key]; }); } export function createTRPCReact< TRouter extends AnyRouter, TSSRContext = unknown, >( opts?: CreateTRPCReactOptions, ): CreateTRPCReact { const hooks = createRootHooks(opts); const proxy = createHooksInternal(hooks); return proxy as any; }