From 9fec9c83c63d9fc54d0fe90210abbf5c3f7026f7 Mon Sep 17 00:00:00 2001 From: Adam Michel Date: Mon, 24 Feb 2025 15:00:12 -0800 Subject: [PATCH 1/6] Infer select return from useInfiniteQuery --- packages/openapi-react-query/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/openapi-react-query/src/index.ts b/packages/openapi-react-query/src/index.ts index 855b249c9..88a1753f9 100644 --- a/packages/openapi-react-query/src/index.ts +++ b/packages/openapi-react-query/src/index.ts @@ -110,7 +110,7 @@ export type UseInfiniteQueryMethod, + InferSelectReturnType, Options["select"]>, Response["data"], QueryKey, unknown @@ -125,7 +125,7 @@ export type UseInfiniteQueryMethod, options: Options, queryClient?: QueryClient, -) => UseInfiniteQueryResult, Response["error"]>; +) => UseInfiniteQueryResult, Options["select"]>, Response["error"]>; export type UseSuspenseQueryMethod>, Media extends MediaType> = < Method extends HttpMethod, From 8911c2bcc257f24d13264053c91c543f42da5570 Mon Sep 17 00:00:00 2001 From: Adam Michel Date: Mon, 24 Feb 2025 15:08:07 -0800 Subject: [PATCH 2/6] Include useInfiniteQuery in docs and update --- docs/.vitepress/en.ts | 2 ++ docs/openapi-react-query/use-infinite-query.md | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/.vitepress/en.ts b/docs/.vitepress/en.ts index e07553cdd..653374764 100644 --- a/docs/.vitepress/en.ts +++ b/docs/.vitepress/en.ts @@ -74,7 +74,9 @@ export default defineConfig({ { text: "useQuery", link: "/use-query" }, { text: "useMutation", link: "/use-mutation" }, { text: "useSuspenseQuery", link: "/use-suspense-query" }, + { text: "useInfiniteQuery", link: "/use-infinite-query" }, { text: "queryOptions", link: "/query-options" }, + { text: "About", link: "/about" }, ], }, { diff --git a/docs/openapi-react-query/use-infinite-query.md b/docs/openapi-react-query/use-infinite-query.md index 86bcbad1e..7824baa1a 100644 --- a/docs/openapi-react-query/use-infinite-query.md +++ b/docs/openapi-react-query/use-infinite-query.md @@ -105,6 +105,7 @@ const query = $api.useInfiniteQuery( - Only required if the OpenApi schema requires parameters. - The options `params` are used as key. See [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for more information. - `infiniteQueryOptions` + - `pageParamName` The query param name used for pagination, `"cursor"` by default. - The original `useInfiniteQuery` options. - [See more information](https://tanstack.com/query/latest/docs/framework/react/reference/useInfiniteQuery) - `queryClient` From eaabef524f041f4693bafe5f3753600912b596ae Mon Sep 17 00:00:00 2001 From: Adam Michel Date: Mon, 24 Feb 2025 15:21:25 -0800 Subject: [PATCH 3/6] Add type test for selects on useInfiniteQuery --- .../openapi-react-query/test/index.test.tsx | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/packages/openapi-react-query/test/index.test.tsx b/packages/openapi-react-query/test/index.test.tsx index 5ccda7a42..3dd84f87a 100644 --- a/packages/openapi-react-query/test/index.test.tsx +++ b/packages/openapi-react-query/test/index.test.tsx @@ -1087,5 +1087,69 @@ describe("client", () => { const allItems = result.current.data?.pages.flatMap((page) => page.items); expect(allItems).toEqual([1, 2, 3, 4, 5, 6]); }); + it('should use return type from select option', async () => { + const fetchClient = createFetchClient({ baseUrl }); + const client = createClient(fetchClient); + + // First page request handler + const firstRequestHandler = useMockRequestHandler({ + baseUrl, + method: "get", + path: "/paginated-data", + status: 200, + body: { items: [1, 2, 3], nextPage: 1 }, + }); + + const { result, rerender } = renderHook( + () => + client.useInfiniteQuery( + "get", + "/paginated-data", + { + params: { + query: { + limit: 3, + }, + }, + }, + { + getNextPageParam: (lastPage) => lastPage.nextPage, + initialPageParam: 0, + select: (data) => data.pages.flatMap((page) => page.items).filter((item) => item !== undefined), + }, + ), + { wrapper }, + ); + + // Wait for initial query to complete + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + expectTypeOf(result.current.data).toEqualTypeOf(); + expect(result.current.data).toEqual([1, 2, 3]); + + // Set up mock for second page before triggering next page fetch + const secondRequestHandler = useMockRequestHandler({ + baseUrl, + method: "get", + path: "/paginated-data", + status: 200, + body: { items: [4, 5, 6], nextPage: 2 }, + }); + + // Fetch next page + await act(async () => { + await result.current.fetchNextPage(); + // Force a rerender to ensure state is updated + rerender(); + }); + + // Wait for second page to be fetched and verify loading states + await waitFor(() => { + expect(result.current.isFetching).toBe(false); + expect(result.current.hasNextPage).toBe(true); + }); + + expect(result.current.data).toEqual([1, 2, 3, 4, 5, 6]); + }); }); }); From 63ed247c13179e54f0b32f503e10349b32f461ae Mon Sep 17 00:00:00 2001 From: Adam Michel Date: Mon, 24 Feb 2025 15:30:05 -0800 Subject: [PATCH 4/6] Add changeset --- .changeset/seven-monkeys-fetch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/seven-monkeys-fetch.md diff --git a/.changeset/seven-monkeys-fetch.md b/.changeset/seven-monkeys-fetch.md new file mode 100644 index 000000000..10e4e6e32 --- /dev/null +++ b/.changeset/seven-monkeys-fetch.md @@ -0,0 +1,5 @@ +--- +"openapi-react-query": minor +--- + +[#2169](https://github.com/openapi-ts/openapi-typescript/pull/2169): Infer returned `data` type from `select` option when used with the `useInfiniteQuery` method. From cab51d400aef479bbd88c3f0267723a3ce1ce18f Mon Sep 17 00:00:00 2001 From: Adam Michel Date: Mon, 24 Feb 2025 15:34:21 -0800 Subject: [PATCH 5/6] Fix linter errors --- packages/openapi-react-query/src/index.ts | 5 ++++- packages/openapi-react-query/test/index.test.tsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/openapi-react-query/src/index.ts b/packages/openapi-react-query/src/index.ts index 88a1753f9..97fd9ce1e 100644 --- a/packages/openapi-react-query/src/index.ts +++ b/packages/openapi-react-query/src/index.ts @@ -125,7 +125,10 @@ export type UseInfiniteQueryMethod, options: Options, queryClient?: QueryClient, -) => UseInfiniteQueryResult, Options["select"]>, Response["error"]>; +) => UseInfiniteQueryResult< + InferSelectReturnType, Options["select"]>, + Response["error"] +>; export type UseSuspenseQueryMethod>, Media extends MediaType> = < Method extends HttpMethod, diff --git a/packages/openapi-react-query/test/index.test.tsx b/packages/openapi-react-query/test/index.test.tsx index 3dd84f87a..1062bafd7 100644 --- a/packages/openapi-react-query/test/index.test.tsx +++ b/packages/openapi-react-query/test/index.test.tsx @@ -1087,7 +1087,7 @@ describe("client", () => { const allItems = result.current.data?.pages.flatMap((page) => page.items); expect(allItems).toEqual([1, 2, 3, 4, 5, 6]); }); - it('should use return type from select option', async () => { + it("should use return type from select option", async () => { const fetchClient = createFetchClient({ baseUrl }); const client = createClient(fetchClient); From 3c7008940ca6c8d3a22ddb9056e6651b393f2bd1 Mon Sep 17 00:00:00 2001 From: Adam Michel Date: Thu, 1 May 2025 16:15:23 -0700 Subject: [PATCH 6/6] Whoops, bad rebase, fixed --- docs/.vitepress/en.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/.vitepress/en.ts b/docs/.vitepress/en.ts index 653374764..b70514df7 100644 --- a/docs/.vitepress/en.ts +++ b/docs/.vitepress/en.ts @@ -76,7 +76,6 @@ export default defineConfig({ { text: "useSuspenseQuery", link: "/use-suspense-query" }, { text: "useInfiniteQuery", link: "/use-infinite-query" }, { text: "queryOptions", link: "/query-options" }, - { text: "About", link: "/about" }, ], }, {