UNPKG

react-query-kit

Version:

🕊️ A toolkit for ReactQuery that make ReactQuery hooks more reusable and typesafe

848 lines (775 loc) • 22.3 kB
import type { DataTag, DefaultError, DefinedUseInfiniteQueryResult, DefinedUseQueryResult, InfiniteData, InfiniteQueryObserverSuccessResult, MutationFunctionContext, MutationKey, QueryClient, QueryFunction, QueryFunctionContext, QueryKey, QueryKeyHashFunction, QueryObserverSuccessResult, SkipToken, UseInfiniteQueryOptions, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult, UseQueryOptions, UseQueryResult, } from '@tanstack/react-query' // utils type CompatibleWithV4<V5, V4> = InfiniteData<unknown> extends UseInfiniteQueryResult< InfiniteData<unknown> >['data'] ? V5 : V4 type CompatibleWithTwoV5<V6Generics, V5Generics> = UseInfiniteQueryOptions< unknown, DefaultError, unknown, QueryKey, unknown > extends never ? V5Generics : V6Generics type CompatibleUseInfiniteQueryOptions<TFnData, TData, TError, TPageParam> = CompatibleWithV4< CompatibleWithTwoV5< UseInfiniteQueryOptions<TFnData, TError, TData, QueryKey, TPageParam>, // @ts-ignore UseInfiniteQueryOptions< TFnData, TError, TData, TFnData, QueryKey, TPageParam > >, // @ts-ignore UseInfiniteQueryOptions<TFnData, TError, TData, TFnData, QueryKey> > type CompatibleInfiniteData<TFnData, TPageParam> = CompatibleWithV4< InfiniteData<TFnData, TPageParam>, InfiniteData<TFnData> > type NonUndefinedGuard<T> = T extends undefined ? never : T type WithRequired<T, K extends keyof T> = T & { [_ in K]: {} } type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]> } : T type DefaultTo<T, D> = unknown extends T ? D : T /** * Register global options through declaration merging, e.g. set * `strictVariables: true` to require `variables` at the call site. */ // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface Register {} // Variables can only be left out when the fetcher accepts `undefined`, // which is what it receives then type RequiresVariables<TVariables> = Register extends { strictVariables: true } ? undefined extends TVariables ? false : true : false type WithRequiredVariables<TOptions, TVariables> = RequiresVariables<TVariables> extends true ? TOptions & { variables: CompatibleWithV4<TVariables | SkipToken, TVariables> } : TOptions type QueryHookArgs<TOptions, TVariables> = RequiresVariables<TVariables> extends true ? [ options: WithRequiredVariables<TOptions, TVariables>, queryClient?: CompatibleWithV4<QueryClient, void> ] : [options?: TOptions, queryClient?: CompatibleWithV4<QueryClient, void>] export type CompatibleError = CompatibleWithV4<DefaultError, Error> export type Fetcher<TFnData, TVariables = void, TPageParam = never> = ( variables: TVariables, context: QueryFunctionContext<QueryKey, TPageParam> ) => TFnData | Promise<TFnData> export type AdditionalQueryOptions<TFnData, TVariables, TPageParam = never> = { fetcher: Fetcher<TFnData, TVariables, TPageParam> variables?: TVariables } type inferMiddlewareHook<T extends (...args: any) => any> = ( options: inferCreateOptions<T>, queryClient?: CompatibleWithV4<QueryClient, void> ) => ReturnType<T> export type Middleware< T extends (...args: any) => any = QueryHook<any, any, any> > = (hook: inferMiddlewareHook<T>) => inferMiddlewareHook<T> export type ExposeFetcher<TFnData, TVariables = void, TPageParam = never> = ( variables: TVariables, context?: Partial<QueryFunctionContext<QueryKey, TPageParam>> ) => TFnData | Promise<TFnData> export type ExposeMethods<TFnData, TVariables, TError, TPageParam = never> = { fetcher: ExposeFetcher<TFnData, TVariables, TPageParam> getKey: ( variables?: DeepPartial<TVariables> ) => CompatibleWithV4< DataTag< QueryKey, [TPageParam] extends [never] ? TFnData : InfiniteData<TFnData, TPageParam> >, QueryKey > getFetchOptions: ( variables: TVariables extends void ? CompatibleWithV4<TVariables | SkipToken, TVariables> | void : CompatibleWithV4<TVariables | SkipToken, TVariables> ) => Pick< ReturnType< ExposeMethods<TFnData, TVariables, TError, TPageParam>['getOptions'] >, // @ts-ignore [TPageParam] extends [never] ? 'queryKey' | 'queryFn' | 'queryKeyHashFn' | 'gcTime' | 'staleTime' : | 'queryKey' | 'queryFn' | 'queryKeyHashFn' | 'gcTime' | 'staleTime' | 'getNextPageParam' | 'getPreviousPageParam' | 'initialPageParam' > getOptions: ( variables: TVariables extends void ? CompatibleWithV4<TVariables | SkipToken, TVariables> | void : CompatibleWithV4<TVariables | SkipToken, TVariables> ) => [TPageParam] extends [never] ? CompatibleWithV4< UseQueryOptions<TFnData, TError, TFnData, QueryKey> & { queryKey: DataTag<QueryKey, TFnData> queryFn?: Exclude< UseQueryOptions<TFnData, TError, TFnData, QueryKey>['queryFn'], SkipToken > }, // Not work to infer TError in v4 { queryKey: QueryKey queryFn: QueryFunction<TFnData, QueryKey> queryKeyHashFn?: QueryKeyHashFunction<QueryKey> } > : CompatibleUseInfiniteQueryOptions< TFnData, TFnData, TError, TPageParam > & { queryKey: CompatibleWithV4< DataTag<QueryKey, InfiniteData<TFnData, TPageParam>>, QueryKey > queryFn?: Exclude< CompatibleUseInfiniteQueryOptions< TFnData, TFnData, TError, TPageParam >['queryFn'], SkipToken > } } type Clone<T> = T extends infer TClone ? TClone : never // query hook export interface CreateQueryOptions< TFnData = unknown, TVariables = void, TError = CompatibleError > extends Omit< UseQueryOptions<TFnData, TError, TFnData, QueryKey>, 'queryKey' | 'queryFn' | 'select' >, AdditionalQueryOptions<TFnData, TVariables> { queryKey: QueryKey use?: Middleware< QueryHook<Clone<TFnData>, Clone<TVariables>, Clone<TError>> >[] variables?: TVariables } export interface QueryHookOptions<TFnData, TError, TData, TVariables> extends Omit< UseQueryOptions<TFnData, TError, TData, QueryKey>, 'queryKey' | 'queryFn' | 'queryKeyHashFn' > { use?: Middleware<QueryHook<TFnData, TVariables, TError>>[] variables?: CompatibleWithV4<TVariables | SkipToken, TVariables> } export interface DefinedQueryHookOptions<TFnData, TError, TData, TVariables> extends Omit< QueryHookOptions<TFnData, TError, TData, TVariables>, 'initialData' > { initialData: NonUndefinedGuard<TFnData> | (() => NonUndefinedGuard<TFnData>) } export type QueryHookResult<TData, TError> = UseQueryResult<TData, TError> export type DefinedQueryHookResult<TData, TError> = DefinedUseQueryResult< TData, TError > export interface QueryHook< TFnData = unknown, TVariables = void, TError = CompatibleError > extends ExposeMethods<TFnData, TVariables, TError> { <TData = TFnData>( options: WithRequiredVariables< DefinedQueryHookOptions<TFnData, TError, TData, TVariables>, TVariables >, queryClient?: CompatibleWithV4<QueryClient, void> ): DefinedQueryHookResult<TData, TError> <TData = TFnData>( ...args: QueryHookArgs< QueryHookOptions<TFnData, TError, TData, TVariables>, TVariables > ): QueryHookResult<TData, TError> } // suspense query hook export interface CreateSuspenseQueryOptions< TFnData = unknown, TVariables = void, TError = CompatibleError > extends Omit< UseQueryOptions<TFnData, TError, TFnData, QueryKey>, | 'queryKey' | 'queryFn' | 'enabled' | 'select' | 'suspense' | 'throwOnError' | 'placeholderData' | 'keepPreviousData' | 'useErrorBoundary' >, AdditionalQueryOptions<TFnData, TVariables> { queryKey: QueryKey use?: Middleware< SuspenseQueryHook<Clone<TFnData>, Clone<TVariables>, Clone<TError>> >[] variables?: TVariables } export interface SuspenseQueryHookOptions<TFnData, TError, TData, TVariables> extends Omit< UseQueryOptions<TFnData, TError, TData, QueryKey>, | 'queryKey' | 'queryFn' | 'queryKeyHashFn' | 'enabled' | 'suspense' | 'throwOnError' | 'placeholderData' | 'keepPreviousData' | 'useErrorBoundary' > { use?: Middleware<SuspenseQueryHook<TFnData, TVariables, TVariables>>[] variables?: CompatibleWithV4<TVariables | SkipToken, TVariables> } export type SuspenseQueryHookResult<TData, TError> = Omit< QueryObserverSuccessResult<TData, TError>, 'isPlaceholderData' | 'isPreviousData' > export interface SuspenseQueryHook< TFnData = unknown, TVariables = void, TError = CompatibleError > extends ExposeMethods<TFnData, TVariables, TError> { <TData = TFnData>( ...args: QueryHookArgs< SuspenseQueryHookOptions<TFnData, TError, TData, TVariables>, TVariables > ): SuspenseQueryHookResult<TData, TError> } // infinite query hook export interface CreateInfiniteQueryOptions< TFnData = unknown, TVariables = void, TError = CompatibleError, TPageParam = number > extends Omit< CompatibleUseInfiniteQueryOptions<TFnData, TFnData, TError, TPageParam>, 'queryKey' | 'queryFn' | 'select' >, AdditionalQueryOptions<TFnData, TVariables, TPageParam> { queryKey: QueryKey use?: Middleware< InfiniteQueryHook< Clone<TFnData>, Clone<TVariables>, Clone<TError>, Clone<TPageParam> > >[] variables?: TVariables } export interface InfiniteQueryHookOptions< TFnData, TError, TData, TVariables, TPageParam = number > extends Omit< CompatibleUseInfiniteQueryOptions<TFnData, TData, TError, TPageParam>, | 'queryKey' | 'queryFn' | 'queryKeyHashFn' | 'initialPageParam' | 'getPreviousPageParam' | 'getNextPageParam' > { use?: Middleware<InfiniteQueryHook<TFnData, TVariables, TError, TPageParam>>[] variables?: CompatibleWithV4<TVariables | SkipToken, TVariables> } export interface DefinedInfiniteQueryHookOptions< TFnData, TError, TData, TVariables, TPageParam = number > extends Omit< InfiniteQueryHookOptions<TFnData, TError, TData, TVariables, TPageParam>, 'initialData' > { initialData: | NonUndefinedGuard<CompatibleInfiniteData<TFnData, TPageParam>> | (() => NonUndefinedGuard<CompatibleInfiniteData<TFnData, TPageParam>>) } export type InfiniteQueryHookResult<TData, TError> = UseInfiniteQueryResult< TData, TError > export type DefinedInfiniteQueryHookResult<TData, TError> = CompatibleWithV4< DefinedUseInfiniteQueryResult<TData, TError>, WithRequired<UseInfiniteQueryResult<TData, TError>, 'data'> > export interface InfiniteQueryHook< TFnData = unknown, TVariables = void, TError = CompatibleError, TPageParam = number > extends ExposeMethods<TFnData, TVariables, TError, TPageParam> { <TData = CompatibleWithV4<InfiniteData<TFnData, TPageParam>, TFnData>>( options: WithRequiredVariables< DefinedInfiniteQueryHookOptions< TFnData, TError, TData, TVariables, TPageParam >, TVariables >, queryClient?: CompatibleWithV4<QueryClient, void> ): DefinedInfiniteQueryHookResult<TData, TError> <TData = CompatibleWithV4<InfiniteData<TFnData, TPageParam>, TFnData>>( ...args: QueryHookArgs< InfiniteQueryHookOptions<TFnData, TError, TData, TVariables, TPageParam>, TVariables > ): InfiniteQueryHookResult<TData, TError> } // infinite sususpense query hook export interface CreateSuspenseInfiniteQueryOptions< TFnData = unknown, TVariables = void, TError = CompatibleError, TPageParam = number > extends Omit< CompatibleUseInfiniteQueryOptions<TFnData, TFnData, TError, TPageParam>, | 'queryKey' | 'queryFn' | 'enabled' | 'select' | 'suspense' | 'throwOnError' | 'placeholderData' | 'keepPreviousData' | 'useErrorBoundary' >, AdditionalQueryOptions<TFnData, TVariables, TPageParam> { queryKey: QueryKey use?: Middleware< SuspenseInfiniteQueryHook< Clone<TFnData>, Clone<TVariables>, Clone<TError>, Clone<TPageParam> > >[] variables?: TVariables } export interface SuspenseInfiniteQueryHookOptions< TFnData, TError, TData, TVariables, TPageParam = number > extends Omit< CompatibleUseInfiniteQueryOptions<TFnData, TData, TError, TPageParam>, | 'queryKey' | 'queryFn' | 'queryKeyHashFn' | 'enabled' | 'initialPageParam' | 'getPreviousPageParam' | 'getNextPageParam' | 'suspense' | 'throwOnError' | 'placeholderData' | 'keepPreviousData' | 'useErrorBoundary' > { use?: Middleware<SuspenseInfiniteQueryHook<TFnData, TVariables, TVariables>>[] variables?: CompatibleWithV4<TVariables | SkipToken, TVariables> } export type SuspenseInfiniteQueryHookResult<TData, TError> = Omit< InfiniteQueryObserverSuccessResult<TData, TError>, 'isPlaceholderData' | 'isPreviousData' > export interface SuspenseInfiniteQueryHook< TFnData = unknown, TVariables = void, TError = CompatibleError, TPageParam = number > extends ExposeMethods<TFnData, TVariables, TError, TPageParam> { <TData = CompatibleWithV4<InfiniteData<TFnData, TPageParam>, TFnData>>( ...args: QueryHookArgs< SuspenseInfiniteQueryHookOptions< TFnData, TError, TData, TVariables, TPageParam >, TVariables > ): SuspenseInfiniteQueryHookResult<TData, TError> } // mutation hook export interface CreateMutationOptions< TData = unknown, TVariables = void, TError = CompatibleError, TContext = unknown > extends UseMutationOptions<TData, TError, TVariables, TContext> { use?: Middleware<MutationHook<TData, TVariables, TError>>[] } export interface MutationHookOptions<TData, TError, TVariables, TContext> extends Omit< UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn' | 'mutationKey' > { use?: Middleware<MutationHook<TData, TVariables, TError>>[] } export type MutationHookResult< TData = unknown, TError = CompatibleError, TVariables = void, TContext = unknown > = UseMutationResult<TData, TError, TVariables, TContext> export type ExposeMutationFn<TData = unknown, TVariables = void> = [ TVariables ] extends [void] ? ( variables?: TVariables, context?: Partial<MutationFunctionContext> ) => Promise<TData> : ( variables: TVariables, context?: Partial<MutationFunctionContext> ) => Promise<TData> export interface ExposeMutationMethods< TData = unknown, TVariables = void, TError = CompatibleError, TDefaultContext = unknown > { getKey: () => MutationKey | undefined getOptions: () => UseMutationOptions< TData, TError, TVariables, TDefaultContext > mutationFn: ExposeMutationFn<TData, TVariables> } export interface MutationHook< TData = unknown, TVariables = void, TError = CompatibleError, TDefaultContext = unknown > extends ExposeMutationMethods<TData, TVariables, TError, TDefaultContext> { <TContext = TDefaultContext>( options?: MutationHookOptions<TData, TError, TVariables, TContext>, queryClient?: CompatibleWithV4<QueryClient, void> ): MutationHookResult<TData, TError, TVariables, TContext> } // infer types export type inferVariables<T> = T extends { fetcher: ExposeFetcher<any, infer TVariables, infer _TPageParam> } ? TVariables : T extends ExposeMutationMethods<any, infer TVariables, any, any> ? TVariables : never export type inferData<T> = T extends { fetcher: ExposeFetcher<infer TFnData, any, infer TPageParam> } ? [TPageParam] extends [never] ? TFnData : CompatibleInfiniteData<TFnData, TPageParam> : T extends ExposeMutationMethods<infer TFnData, any, any, any> ? TFnData : never export type inferFnData<T> = T extends { fetcher: ExposeFetcher<infer TFnData, any, infer _TPageParam> } ? TFnData : T extends ExposeMutationMethods<infer TFnData, any, any, any> ? TFnData : never export type inferError<T> = T extends ExposeMethods<any, any, infer TError> ? TError : T extends ExposeMethods<any, any, infer TError, any> ? TError : T extends ExposeMutationMethods<any, any, infer TError, any> ? TError : never export type inferOptions<T> = T extends QueryHook< infer TFnData, infer TVariables, infer TError > ? WithRequiredVariables< QueryHookOptions<TFnData, TError, TFnData, TVariables>, TVariables > : T extends SuspenseQueryHook<infer TFnData, infer TVariables, infer TError> ? WithRequiredVariables< SuspenseQueryHookOptions<TFnData, TError, TFnData, TVariables>, TVariables > : T extends InfiniteQueryHook< infer TFnData, infer TVariables, infer TError, infer TPageParam > ? WithRequiredVariables< InfiniteQueryHookOptions< TFnData, TError, CompatibleWithV4<InfiniteData<TFnData, TPageParam>, TFnData>, TVariables, TPageParam >, TVariables > : T extends SuspenseInfiniteQueryHook< infer TFnData, infer TVariables, infer TError, infer TPageParam > ? WithRequiredVariables< SuspenseInfiniteQueryHookOptions< TFnData, TError, CompatibleWithV4<InfiniteData<TFnData, TPageParam>, TFnData>, TVariables, TPageParam >, TVariables > : T extends MutationHook<infer TFnData, infer TVariables, infer TError> ? MutationHookOptions<TFnData, TError, TVariables, unknown> : never export type inferCreateOptions<T> = T extends QueryHook< infer TFnData, infer TVariables, infer TError > ? CreateQueryOptions<TFnData, TVariables, TError> : T extends SuspenseQueryHook<infer TFnData, infer TVariables, infer TError> ? CreateSuspenseQueryOptions<TFnData, TVariables, TError> : T extends InfiniteQueryHook< infer TFnData, infer TVariables, infer TError, infer TPageParam > ? CreateInfiniteQueryOptions<TFnData, TVariables, TError, TPageParam> : T extends SuspenseInfiniteQueryHook< infer TFnData, infer TVariables, infer TError, infer TPageParam > ? CreateSuspenseInfiniteQueryOptions<TFnData, TVariables, TError, TPageParam> : T extends MutationHook< infer TFnData, infer TVariables, infer TError, infer TContext > ? CreateMutationOptions<TFnData, TVariables, TError, TContext> : never // router export type RouterQueryOptions< TFnData, TVariables = void, TError = CompatibleError > = Omit<CreateQueryOptions<TFnData, TVariables, TError>, 'queryKey'> export type RouterQuery< TFnData, TVariables = void, TError = CompatibleError > = RouterQueryOptions<TFnData, TVariables, TError> & { _routerType: `q` } export type ResolvedRouterQuery< TFnData, TVariables = void, TError = CompatibleError > = { useQuery: QueryHook<TFnData, TVariables, TError> useSuspenseQuery: SuspenseQueryHook<TFnData, TVariables, TError> } & ExposeMethods<TFnData, TVariables, TError> export type RouterInfiniteQueryOptions< TFnData, TVariables = void, TError = CompatibleError, TPageParam = number > = Omit< CreateInfiniteQueryOptions<TFnData, TVariables, TError, TPageParam>, 'queryKey' > export type RouterInfiniteQuery< TFnData, TVariables = void, TError = CompatibleError, TPageParam = number > = RouterInfiniteQueryOptions< TFnData, TVariables, TError, Clone<TPageParam> > & { _routerType: `inf` } export type ResolvedRouterInfiniteQuery< TFnData, TVariables = void, TError = CompatibleError, TPageParam = number > = { useInfiniteQuery: InfiniteQueryHook<TFnData, TVariables, TError, TPageParam> useSuspenseInfiniteQuery: SuspenseInfiniteQueryHook< TFnData, TVariables, TError, TPageParam > } & ExposeMethods<TFnData, TVariables, TError, TPageParam> export type RouterMutationOptions< TData = unknown, TVariables = void, TError = CompatibleError, TContext = unknown > = Omit< CreateMutationOptions<TData, TVariables, TError, TContext>, 'mutationKey' > export type RouterMutation< TData = unknown, TVariables = void, TError = CompatibleError, TContext = unknown > = RouterMutationOptions<TData, TVariables, TError, TContext> & { _routerType: `m` } export type ResolvedRouterMutation< TData = unknown, TVariables = void, TError = CompatibleError, TContext = unknown > = { useMutation: MutationHook< TData, DefaultTo<TVariables, void>, DefaultTo<TError, CompatibleError>, TContext > } & ExposeMutationMethods< TData, DefaultTo<TVariables, void>, DefaultTo<TError, CompatibleError>, TContext > export type RouterLeaf = | RouterQuery<any, any, any> | RouterInfiniteQuery<any, any, any, any> | RouterMutation<any, any, any, any> export type RouterConfig = { _routerType?: never } & { [k: string]: RouterLeaf | RouterConfig } export type CreateRouter<TConfig extends RouterConfig> = { [K in keyof TConfig]: TConfig[K] extends RouterMutation< infer TFnData, infer TVariables, infer TError, infer TContext > ? ResolvedRouterMutation< TFnData, DefaultTo<TVariables, void>, DefaultTo<TError, CompatibleError>, TContext > : TConfig[K] extends RouterInfiniteQuery< infer TFnData, infer TVariables, infer TError, infer TPageParam > ? ResolvedRouterInfiniteQuery< TFnData, DefaultTo<TVariables, void>, DefaultTo<TError, CompatibleError>, DefaultTo<TPageParam, number> > : TConfig[K] extends RouterQuery< infer TFnData, infer TVariables, infer TError > ? ResolvedRouterQuery< TFnData, DefaultTo<TVariables, void>, DefaultTo<TError, CompatibleError> > : TConfig[K] extends RouterConfig ? CreateRouter<TConfig[K]> : never } & { getKey: () => QueryKey }