Skip to content

TypeScript: Selectors for inifinite query less expressive #3065

Closed
@jasperkuperus

Description

@jasperkuperus

Describe the bug
Selectors in combination with useQuery look very good. Creating multiple hooks on top of the original useQuery hook, allowing you to get different parts of the data out the query result as described in https://tkdodo.eu/blog/react-query-data-transformations in particular (e.g. useTodosCount, useTodos, useTodo(id)).

Now, when using useInfiniteQuery, I'm able to do the same thing. But TypeScript won't let me. It forces me into the InfiniteData type, hence the { pages, pageParams } format.

To Reproduce

What I'd like to do is twofold:

  • Get an array of all items concatenated over all pages
  • Get the total count of items available in the backend

Type definitions of a simplified example:

interface Entity {
  id: string;
  // ...
}

interface APIResponse {
  total: number;      // Total number of entities available in the backend
  totalPages: number; // Total number of pages with entities
  items: Entity[];    // The entities for this requested page
}

interface DesiredDataResult {
  total: number;   // Same value as total in APIResponse
  items: Entity[]; // Concatenation of all items on all fetched pages (flatMap of `page.items`)
}

Now, I try to build the DesiredDataResult in the selector:

const { data: result } = useInfiniteQuery(
  ['entities', 'list'],
  async ({ pageParam = 0 }) => getPageFromAPI(pageParam),
  {
    getNextPageParam: (lastPage, allPages) =>
      lastPage.totalPages > allPages.length ? allPages.length : undefined,
    select: React.useCallback(
      (data: InfiniteData<APIResponse>) => ({
        total: data.pages[0].total,
        entities: data.pages.flatMap((page) => page.items),
      }),
      [],
    ),
  },
);

And I get this TypeScript error. It wants me to use the { pages, pageParams } type.

Type '(data: InfiniteData<APIResponse>) => { total: number; entities: Entity[]; }' is not assignable to type '(data: InfiniteData<APIResponse>) => InfiniteData<APIResponse>'.
  Type '{ total: number; entities: Entity[]; }' is missing the following properties from type 'InfiniteData<APIResponse>': pages, pageParams ts(2322)

Therefore, selectors in combination with useInfiniteQuery are less expressive than with useQuery. Maybe I'm missing something?

Expected behavior
I would have expected to be able to apply selectors with the same expressiveness as useQuery on useInfiniteQuery.

Screenshots
Screenshot 2021-12-07 at 09 03 29

Desktop (please complete the following information):

  • OS: macOS
  • Browser: Safari
  • Version: 14.1.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions