Properly type useInfiniteQuery to respect the select result
Test: https://codesandbox.io/s/tannerlinsley-react-query-forked-gw8jm2?file=/src/index.tsx
Currently the type returned by useInfiniteQuery is not honoring the result of the select function. This is due to the fact that it is wrapped at one point in InfiniteData<TData> which strips the context once it is passed to the Query which doesn't have any wrapping.
The solution was to allow InfiniteData to have two parameters, one would be the normal TData and the other is a type parameter SData which represents the result of the select fn. This way it doesn't strip the context and can store both. The SData ends up taking precedence, but rules do still exist:
- Select must return a compatible type to
InfiniteData<TData>(it must have a pages and pagesParams property and both must be arrays, but they can be made a diff type if needed). - Any extra keys can be returned on top of those keys and the type is automatically inferred.
Such that:
type FetchResult = {
totalPages: number;
page: number;
items: {
n: number;
}[];
};
async function exampleFetch(page: number): Promise<FetchResult> {
return {
totalPages: 50,
page,
items: [{ n: page + 1 }, { n: page + 2 }, { n: page + 3 }],
};
}
/*
function transformResult(data: InfiniteData<FetchResult>) {
return {
...data,
items: data.pages.flatMap(x => x.items),
};
}
export function useExampleInfiniteQuery() {
const result = useInfiniteQuery({
queryKey: ['example'],
queryFn: ({ pageParam = 1 }) => exampleFetch(pageParam),
getNextPageParam: (lastPage: FetchResult) =>
lastPage.page === lastPage.totalPages ? undefined : lastPage.page + 1,
getPreviousPageParam: () => undefined,
select: useCallback(data => transformResult(data), []),
});
// correct
const data: InfiniteData<FetchResult, {
items: {
n: number;
}[];
}> | undefined = result.data
return result.data?.items;
}
It also allows overwriting the pages and pagesParams keys, but it will error if the return transformation does not include them and they must be arrays.
So:
// @ts-expect-error - type must have pages and pageParams arrays
function transformResult(data: InfiniteData<FetchResult>) {
return {
items: data.pages.flatMap(x => x.items),
};
}
/*
InfiniteData<never, {
pages: never[];
pageParams: never[];
items: {
n: number;
}[];
}>
*/
function transformResult(data: InfiniteData<FetchResult>) {
return {
pages: [],
pageParams: [],
items: data.pages.flatMap(x => x.items),
};
}
/*
InfiniteData<number, {
pages: number[];
pageParams: number[];
items: {
n: number;
}[];
}>
*/
function transformResult(data: InfiniteData<FetchResult>) {
return {
pages: [1, 2, 3],
pageParams: [1, 2, 3],
items: data.pages.flatMap(x => x.items),
};
}
closes #3065
The latest updates on your projects. Learn more about Vercel for Git ↗︎
| Name | Status | Preview | Updated |
|---|---|---|---|
| react-query | ✅ Ready (Inspect) | Visit Preview | May 19, 2022 at 6:04AM (UTC) |
This pull request is automatically built and testable in CodeSandbox.
To see build info of the built libraries, click here or the icon next to each commit SHA.
Latest deployment of this branch, based on commit 4cca36c65ca315d549b9cadfc84ca7f988c7951b:
| Sandbox | Source |
|---|---|
| tannerlinsley/react-query: basic | Configuration |
| tannerlinsley/react-query | Configuration |
Codecov Report
Merging #3625 (9f6c992) into master (5848fab) will not change coverage. The diff coverage is
n/a.
:exclamation: Current head 9f6c992 differs from pull request most recent head 4cca36c. Consider uploading reports for the commit 4cca36c to get more accurate results
@@ Coverage Diff @@
## master #3625 +/- ##
=======================================
Coverage 96.35% 96.35%
=======================================
Files 45 45
Lines 2278 2278
Branches 637 637
=======================================
Hits 2195 2195
Misses 80 80
Partials 3 3
| Impacted Files | Coverage Δ | |
|---|---|---|
| src/core/mutation.ts | 100.00% <ø> (ø) |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact),ø = not affected,? = missing dataPowered by Codecov. Last update 5848fab...4cca36c. Read the comment docs.
Not sure why this failed for node 16? Seems odd it works for 14 and 12? It says that the objects are not equal - I did not make a single change to the codebase, it was all type level changes. Not to mention 12 and 14 were fine... and i developed with 16 and the tests passed.
Not sure why this failed for node 16? Seems odd it works for 14 and 12? It says that the objects are not equal - I did not make a single change to the codebase, it was all type level changes. Not to mention 12 and 14 were fine... and i developed with 16 and the tests passed.
seems like a flaky test :( I've re-run the pipeline
can you please add a type level test that shows that these things are working?
we have some examples, e.g. here:
https://github.com/tannerlinsley/react-query/blob/9f6c992feecb4694758f8767063d8ad89d842c3c/src/react/tests/useQueries.test.tsx#L473-L498
Will do
I am investigating a better fix which will actually work as it actually works but I'm not sure it'll be possible so we may have to include the extra rule for typescript (for now) unless we want to do a major (complete) overhaul to the type design.
Although I have realized there's a problem with infinite query select in that if you use it to transform data you have to transform all elements every time it runs. I understand the reason for it, but I do think there are fundamental concerns with this fn that is worth working out in another place.
@bradennapier how are we with this PR? We have released v4 in the meantime, so there are a couple of conflicts that would need to be addressed please
I am investigating a better fix which will actually work
@bradennapier what's the status here please?
FYI, I will close stale PRs somewhen next week. Please either address the open comments / resolve the merge conflicts or this PR will be closed. Thanks 🙏
if someone wants to pick up this PR where it left off, please feel free. But no feedback for 3 months means I'm gonna close this stale PR.
Any update on this? Or type of select is still not inferred for infinite query?
It's fixed in v5