Skip to content
Closed
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/ripe-singers-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"swr-openapi": patch
---

Narrow excess-property acceptance for query init types
28 changes: 27 additions & 1 deletion docs/swr-openapi/use-infinite.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,33 @@ useInfinite("/something", (pageIndex, previousPageData) => {
});
```

### Enforcing exact param shapes

When returning an object from the `getInit` loader, TypeScript may not always perform excess property checks on the inline object literal. If you want the compiler to reject extra keys in `params.query`/`params.path`, use either of these patterns:

```ts
import type { TypesForRequest } from "swr-openapi";
import type { paths } from "./my-schema";

// Option 1: typed variable
type FindByStatus = TypesForRequest<paths, "get", "/pet/findByStatus">;
const init: FindByStatus["Init"] = {
params: { query: { status: "available" } },
// extra properties here will be rejected by TS
};
useInfinite("/pet/findByStatus", () => init);

// Option 2: satisfies
useInfinite(
"/pet/findByStatus",
() =>
({
params: { query: { status: "available" } },
// extra properties here will be rejected by TS
}) satisfies TypesForRequest<paths, "get", "/pet/findByStatus">["Init"]
);
```

### Using cursors

```ts
Expand Down Expand Up @@ -147,7 +174,6 @@ function useInfinite(path, getInit, config) {
}
```


[oai-fetch-options]: https://openapi-ts.pages.dev/openapi-fetch/api#fetch-options
[swr-api]: https://swr.vercel.app/docs/api
[swr-infinite]: https://swr.vercel.app/docs/pagination#useswrinfinite
Expand Down
40 changes: 40 additions & 0 deletions packages/swr-openapi/src/__test__/types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,46 @@ const useMutate = createMutateHook(
const mutate = useMutate();

describe("types", () => {
describe("excess property checks", () => {
describe("useQuery", () => {
it("rejects extra properties in query params", () => {
useQuery("/pet/findByStatus", {
params: {
query: {
status: "available",
// @ts-expect-error extra property should be rejected
invalid_property: "nope",
},
},
});
});

it("rejects extra properties in path params", () => {
useQuery("/pet/{petId}", {
params: {
path: {
petId: 5,
// @ts-expect-error extra property should be rejected
invalid_path_param: "nope",
},
},
});
});

it("rejects extra properties in header params", () => {
useQuery("/pet/findByStatus", {
params: {
header: {
"X-Example": "test",
// @ts-expect-error extra property should be rejected
"Invalid-Header": "nope",
},
},
});
});
});
});

describe("key types", () => {
describe("useQuery", () => {
it("accepts config", () => {
Expand Down
5 changes: 3 additions & 2 deletions packages/swr-openapi/src/query-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ export function configureBaseQueryHook(useHook: SWRHook) {
return function useQuery<
Path extends PathsWithMethod<Paths, "get">,
R extends TypesForGetRequest<Paths, Path>,
Init extends R["Init"],
Data extends R["Data"],
Error extends R["Error"] | FetcherError,
Config extends R["SWRConfig"],
>(
path: Path,
...[init, config]: RequiredKeysOf<Init> extends never ? [(Init | null)?, Config?] : [Init | null, Config?]
...[init, config]: RequiredKeysOf<R["Init"]> extends never
? [(R["Init"] | null)?, Config?]
: [R["Init"] | null, Config?]
) {
useDebugValue(`${prefix} - ${path as string}`);

Expand Down
Loading