Skip to content

Instantly share code, notes, and snippets.

@awmichel
Created January 23, 2025 00:48
Show Gist options
  • Save awmichel/0e3aa3d5df6f7891e794895d2c695107 to your computer and use it in GitHub Desktop.
Save awmichel/0e3aa3d5df6f7891e794895d2c695107 to your computer and use it in GitHub Desktop.
import { useInfiniteQuery as useInfiniteQueryOriginal } from "@tanstack/react-query";
export type UseInfiniteQueryMethod<
Paths extends Record<string, Record<HttpMethod, object>>,
Media extends MediaType
> = <
Method extends HttpMethod,
Path extends PathsWithMethod<Paths, Method>,
Init extends MaybeOptionalInit<Paths[Path], Method>,
QueryParams extends QueryParamsFromPaths<Paths, Path, Method>,
PageParam extends keyof QueryParams,
Response extends Required<FetchResponse<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types
Options extends Omit<
UseInfiniteQueryOptions<
Response["data"],
Response["error"],
InfiniteData<Response["data"], NonNullable<QueryParams[PageParam]>>,
QueryKey<Paths, Method, Path>
>,
"queryKey" | "queryFn"
>
>(
method: Method,
path: Path,
pageParamName: PageParam,
...[init, options, queryClient]: RequiredKeysOf<Init> extends never
? [InitWithUnknowns<Init>?, Options?, QueryClient?]
: [InitWithUnknowns<Init>, Options?, QueryClient?]
) => UseInfiniteQueryResult<
InfiniteData<Response["data"], NonNullable<QueryParams[PageParam]>>,
Response["error"]
>;
function useInfiniteQuery(
method,
path,
pageParamName,
...[init, options, queryClient]
) {
return useInfiniteQueryOriginal(
{
queryKey: [method, path, init],
// @ts-expect-error - I couldn't fully resolve the types here, but it seems to work.
queryFn: async ({ signal, pageParam }) => {
const mth = method.toUpperCase() as Uppercase<typeof method>;
// @ts-expect-error - I couldn't fully resolve the types here, but it seems to work.
const fn = fetchClient[mth] as ClientMethod<
paths,
typeof method,
"application/json"
>;
// @ts-expect-error - I couldn't fully resolve the types here, but it seems to work.
const initWithPage: typeof init = {
...init,
signal,
params: {
...init?.params,
query: {
...init?.params?.query,
[pageParamName]: pageParam,
},
},
};
// @ts-expect-error - I couldn't fully resolve the types here, but it seems to work.
const { data, error } = await fn(path, initWithPage);
if (error) {
throw error;
}
return data;
},
...options,
},
queryClient
);
}
useInfiniteQuery(
"get",
"/api/v1/listing_favorites/",
"page",
{ params },
{
staleTime: 300,
placeholderData: keepPreviousData,
maxPages: 10,
initialPageParam: 1,
getNextPageParam: (lastPage) => {
return lastPage.pagination?.next;
},
enabled: authenticated,
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment