Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-query-options-init.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-react-query": patch
---

Reject React Query options passed as request init.
17 changes: 9 additions & 8 deletions packages/openapi-react-query/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ import type { HttpMethod, MediaType, PathsWithMethod, RequiredKeysOf } from "ope
type InferSelectReturnType<TData, TSelect> = TSelect extends (data: TData) => infer R ? R : TData;

type InitWithUnknowns<Init> = Init & { [key: string]: unknown };
// Keep arbitrary fetch init fields while reserving options for React Query itself.
type QueryInit<Init> = InitWithUnknowns<Init> & { [Key in keyof UseQueryOptions]?: never };
type InfiniteQueryInit<Init> = InitWithUnknowns<Init> & { [Key in keyof UseInfiniteQueryOptions]?: never };

export type QueryKey<
Paths extends Record<string, Record<HttpMethod, {}>>,
Expand All @@ -55,9 +58,7 @@ export type QueryOptionsFunction<Paths extends Record<string, Record<HttpMethod,
>(
method: Method,
path: Path,
...[init, options]: RequiredKeysOf<Init> extends never
? [InitWithUnknowns<Init>?, Options?]
: [InitWithUnknowns<Init>, Options?]
...[init, options]: RequiredKeysOf<Init> extends never ? [QueryInit<Init>?, Options?] : [QueryInit<Init>, Options?]
) => NoInfer<
Omit<
UseQueryOptions<
Expand Down Expand Up @@ -99,8 +100,8 @@ export type UseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>,
method: Method,
url: Path,
...[init, options, queryClient]: RequiredKeysOf<Init> extends never
? [InitWithUnknowns<Init>?, Options?, QueryClient?]
: [InitWithUnknowns<Init>, Options?, QueryClient?]
? [QueryInit<Init>?, Options?, QueryClient?]
: [QueryInit<Init>, Options?, QueryClient?]
) => UseQueryResult<InferSelectReturnType<Response["data"], Options["select"]>, Response["error"]>;

export type UseInfiniteQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = <
Expand All @@ -123,7 +124,7 @@ export type UseInfiniteQueryMethod<Paths extends Record<string, Record<HttpMetho
>(
method: Method,
url: Path,
init: InitWithUnknowns<Init>,
init: InfiniteQueryInit<Init>,
options: Options,
queryClient?: QueryClient,
) => UseInfiniteQueryResult<
Expand All @@ -149,8 +150,8 @@ export type UseSuspenseQueryMethod<Paths extends Record<string, Record<HttpMetho
method: Method,
url: Path,
...[init, options, queryClient]: RequiredKeysOf<Init> extends never
? [InitWithUnknowns<Init>?, Options?, QueryClient?]
: [InitWithUnknowns<Init>, Options?, QueryClient?]
? [QueryInit<Init>?, Options?, QueryClient?]
: [QueryInit<Init>, Options?, QueryClient?]
) => UseSuspenseQueryResult<InferSelectReturnType<Response["data"], Options["select"]>, Response["error"]>;

export type UseMutationMethod<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = <
Expand Down
12 changes: 12 additions & 0 deletions packages/openapi-react-query/test/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,18 @@ describe("client", () => {
>();
});

it("should reject query options passed as request init", () => {
const fetchClient = createFetchClient<minimalGetPaths>({ 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;

Expand Down
Loading