From 5e2195fe409f8fa5185ada75baaa45e142d5cf64 Mon Sep 17 00:00:00 2001 From: lprnmns Date: Sun, 30 Aug 2026 18:51:59 +0300 Subject: [PATCH] fix(openapi-react-query): reject query options as request init --- .changeset/fix-query-options-init.md | 5 +++++ packages/openapi-react-query/src/index.ts | 17 +++++++++-------- .../openapi-react-query/test/index.test.tsx | 12 ++++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 .changeset/fix-query-options-init.md diff --git a/.changeset/fix-query-options-init.md b/.changeset/fix-query-options-init.md new file mode 100644 index 000000000..225790b5f --- /dev/null +++ b/.changeset/fix-query-options-init.md @@ -0,0 +1,5 @@ +--- +"openapi-react-query": patch +--- + +Reject React Query options passed as request init. diff --git a/packages/openapi-react-query/src/index.ts b/packages/openapi-react-query/src/index.ts index fb9683164..d81746801 100644 --- a/packages/openapi-react-query/src/index.ts +++ b/packages/openapi-react-query/src/index.ts @@ -30,6 +30,9 @@ import type { HttpMethod, MediaType, PathsWithMethod, RequiredKeysOf } from "ope type InferSelectReturnType = TSelect extends (data: TData) => infer R ? R : TData; type InitWithUnknowns = Init & { [key: string]: unknown }; +// Keep arbitrary fetch init fields while reserving options for React Query itself. +type QueryInit = InitWithUnknowns & { [Key in keyof UseQueryOptions]?: never }; +type InfiniteQueryInit = InitWithUnknowns & { [Key in keyof UseInfiniteQueryOptions]?: never }; export type QueryKey< Paths extends Record>, @@ -55,9 +58,7 @@ export type QueryOptionsFunction( method: Method, path: Path, - ...[init, options]: RequiredKeysOf extends never - ? [InitWithUnknowns?, Options?] - : [InitWithUnknowns, Options?] + ...[init, options]: RequiredKeysOf extends never ? [QueryInit?, Options?] : [QueryInit, Options?] ) => NoInfer< Omit< UseQueryOptions< @@ -99,8 +100,8 @@ export type UseQueryMethod>, method: Method, url: Path, ...[init, options, queryClient]: RequiredKeysOf extends never - ? [InitWithUnknowns?, Options?, QueryClient?] - : [InitWithUnknowns, Options?, QueryClient?] + ? [QueryInit?, Options?, QueryClient?] + : [QueryInit, Options?, QueryClient?] ) => UseQueryResult, Response["error"]>; export type UseInfiniteQueryMethod>, Media extends MediaType> = < @@ -123,7 +124,7 @@ export type UseInfiniteQueryMethod( method: Method, url: Path, - init: InitWithUnknowns, + init: InfiniteQueryInit, options: Options, queryClient?: QueryClient, ) => UseInfiniteQueryResult< @@ -149,8 +150,8 @@ export type UseSuspenseQueryMethod extends never - ? [InitWithUnknowns?, Options?, QueryClient?] - : [InitWithUnknowns, Options?, QueryClient?] + ? [QueryInit?, Options?, QueryClient?] + : [QueryInit, Options?, QueryClient?] ) => UseSuspenseQueryResult, Response["error"]>; export type UseMutationMethod>, Media extends MediaType> = < diff --git a/packages/openapi-react-query/test/index.test.tsx b/packages/openapi-react-query/test/index.test.tsx index 78715e643..61cd4d9a1 100644 --- a/packages/openapi-react-query/test/index.test.tsx +++ b/packages/openapi-react-query/test/index.test.tsx @@ -478,6 +478,18 @@ describe("client", () => { >(); }); + it("should reject query options passed as request init", () => { + const fetchClient = createFetchClient({ baseUrl }); + const client = createClient(fetchClient); + + // @ts-expect-error Query options belong in the fourth argument. + const invalidQuery = () => client.useQuery("get", "/foo", { retry: false }); + const customInit = () => client.useQuery("get", "/foo", { customRequestOption: true }); + expectTypeOf(customInit).toBeFunction(); + + expectTypeOf(invalidQuery).toBeFunction(); + }); + it("passes abort signal to fetch", async () => { let signalPassedToFetch: AbortSignal | undefined;