Repository: reduxjs/redux-toolkit

Problem statement:
infinite query matchFulfilled returns wrong type
```ts
// api
getInfinityScrollThreads: build.infiniteQuery<GetPostsResponse, Args, number>

// slice
extraReducers: (builder) => {
    builder.addMatcher(api.endpoints.getInfiniteQueryPosts.matchFulfilled, (state, action) => {
       const payload = action.payload <-- shows up as GetPostsResponse but is actually { pages: GetPostsResponse[], pageParams: number[] }
    }
```

@markerikson Maybe I'm doing something wrong? 


Hints:
No, that's presumably an actual bug - I didn't think to update the types for the matchers there. Thanks for catching this!
> No, that's presumably an actual bug - I didn't think to update the types for the matchers there. Thanks for catching this!

same issue: 
```ts
providesTags: (result: { pages: GetPostsResponse[], pageParams: number[] }) => []
```


Patch:
diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts
--- a/packages/toolkit/src/query/core/buildThunks.ts
+++ b/packages/toolkit/src/query/core/buildThunks.ts
@@ -26,6 +26,7 @@ import type {
   PageParamFrom,
   QueryArgFrom,
   QueryDefinition,
+  ResultDescription,
   ResultTypeFrom,
 } from '../endpointDefinitions'
 import {
@@ -71,14 +72,14 @@ export type BuildThunksApiEndpointQuery<
 
 export type BuildThunksApiEndpointInfiniteQuery<
   Definition extends InfiniteQueryDefinition<any, any, any, any, any>,
-> = Matchers<QueryThunk, Definition>
+> = Matchers<InfiniteQueryThunk<any>, Definition>
 
 export type BuildThunksApiEndpointMutation<
   Definition extends MutationDefinition<any, any, any, any, any>,
 > = Matchers<MutationThunk, Definition>
 
 type EndpointThunk<
-  Thunk extends QueryThunk | MutationThunk,
+  Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
   Definition extends EndpointDefinition<any, any, any, any>,
 > =
   Definition extends EndpointDefinition<
@@ -94,27 +95,41 @@ type EndpointThunk<
           ATConfig & { rejectValue: BaseQueryError<BaseQueryFn> }
         >
       : never
-    : never
+    : Definition extends InfiniteQueryDefinition<
+          infer QueryArg,
+          infer PageParam,
+          infer BaseQueryFn,
+          any,
+          infer ResultType
+        >
+      ? Thunk extends AsyncThunk<unknown, infer ATArg, infer ATConfig>
+        ? AsyncThunk<
+            InfiniteData<ResultType, PageParam>,
+            ATArg & { originalArgs: QueryArg },
+            ATConfig & { rejectValue: BaseQueryError<BaseQueryFn> }
+          >
+        : never
+      : never
 
 export type PendingAction<
-  Thunk extends QueryThunk | MutationThunk,
+  Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
   Definition extends EndpointDefinition<any, any, any, any>,
 > = ReturnType<EndpointThunk<Thunk, Definition>['pending']>
 
 export type FulfilledAction<
-  Thunk extends QueryThunk | MutationThunk,
+  Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
   Definition extends EndpointDefinition<any, any, any, any>,
 > = ReturnType<EndpointThunk<Thunk, Definition>['fulfilled']>
 
 export type RejectedAction<
-  Thunk extends QueryThunk | MutationThunk,
+  Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
   Definition extends EndpointDefinition<any, any, any, any>,
 > = ReturnType<EndpointThunk<Thunk, Definition>['rejected']>
 
 export type Matcher<M> = (value: any) => value is M
 
 export interface Matchers<
-  Thunk extends QueryThunk | MutationThunk,
+  Thunk extends QueryThunk | MutationThunk | InfiniteQueryThunk<any>,
   Definition extends EndpointDefinition<any, any, any, any>,
 > {
   matchPending: Matcher<PendingAction<Thunk, Definition>>
@@ -645,7 +660,6 @@ export function buildThunks<
           isForcedQueryNeedingRefetch || !cachedData ? blankData : cachedData
         ) as InfiniteData<unknown, unknown>
 
-
         // If the thunk specified a direction and we do have at least one page,
         // fetch the next or previous page
         if ('direction' in arg && arg.direction && existingData.pages.length) {
@@ -960,14 +974,18 @@ export function getPreviousPageParam(
 
 export function calculateProvidedByThunk(
   action: UnwrapPromise<
-    ReturnType<ReturnType<QueryThunk>> | ReturnType<ReturnType<MutationThunk>>
+    | ReturnType<ReturnType<QueryThunk>>
+    | ReturnType<ReturnType<MutationThunk>>
+    | ReturnType<ReturnType<InfiniteQueryThunk<any>>>
   >,
   type: 'providesTags' | 'invalidatesTags',
   endpointDefinitions: EndpointDefinitions,
   assertTagType: AssertTagTypes,
 ) {
   return calculateProvidedBy(
-    endpointDefinitions[action.meta.arg.endpointName][type],
+    endpointDefinitions[action.meta.arg.endpointName][
+      type
+    ] as ResultDescription<any, any, any, any, any>,
     isFulfilled(action) ? action.payload : undefined,
     isRejectedWithValue(action) ? action.payload : undefined,
     action.meta.arg.originalArgs,
diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts
--- a/packages/toolkit/src/query/endpointDefinitions.ts
+++ b/packages/toolkit/src/query/endpointDefinitions.ts
@@ -595,7 +595,7 @@ export interface InfiniteQueryExtraOptions<
 
   providesTags?: ResultDescription<
     TagTypes,
-    ResultType,
+    InfiniteData<ResultType, PageParam>,
     QueryArg,
     BaseQueryError<BaseQuery>,
     BaseQueryMeta<BaseQuery>
diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts
--- a/packages/toolkit/src/query/react/buildHooks.ts
+++ b/packages/toolkit/src/query/react/buildHooks.ts
@@ -940,7 +940,7 @@ export type UseInfiniteQuery<
 export type UseInfiniteQueryState<
   D extends InfiniteQueryDefinition<any, any, any, any, any>,
 > = <R extends Record<string, any> = UseInfiniteQueryStateDefaultResult<D>>(
-  arg: QueryArgFrom<D> | SkipToken,
+  arg: InfiniteQueryArgFrom<D> | SkipToken,
   options?: UseInfiniteQueryStateOptions<D, R>,
 ) => UseInfiniteQueryStateResult<D, R>
 
@@ -977,7 +977,7 @@ export type TypedUseInfiniteQueryState<
 export type UseInfiniteQuerySubscription<
   D extends InfiniteQueryDefinition<any, any, any, any, any>,
 > = (
-  arg: QueryArgFrom<D> | SkipToken,
+  arg: InfiniteQueryArgFrom<D> | SkipToken,
   options?: UseInfiniteQuerySubscriptionOptions<D>,
 ) => UseInfiniteQuerySubscriptionResult<D>
 


Test patch:
diff --git a/packages/toolkit/src/query/tests/infiniteQueries.test-d.ts b/packages/toolkit/src/query/tests/infiniteQueries.test-d.ts
--- a/packages/toolkit/src/query/tests/infiniteQueries.test-d.ts
+++ b/packages/toolkit/src/query/tests/infiniteQueries.test-d.ts
@@ -5,6 +5,7 @@ import {
   QueryStatus,
 } from '@reduxjs/toolkit/query/react'
 import { setupApiStore } from '../../tests/utils/helpers'
+import { createSlice } from '@internal/createSlice'
 
 describe('Infinite queries', () => {
   test('Basic infinite query behavior', async () => {
@@ -54,6 +55,12 @@ describe('Infinite queries', () => {
               InfiniteData<Pokemon[], number>
             >()
           },
+          providesTags: (result) => {
+            expectTypeOf(result).toEqualTypeOf<
+              InfiniteData<Pokemon[], number> | undefined
+            >()
+            return []
+          },
         }),
       }),
     })
@@ -68,6 +75,36 @@ describe('Infinite queries', () => {
 
     expectTypeOf(pokemonApi.useGetInfinitePokemonInfiniteQuery).toBeFunction()
 
+    expectTypeOf(pokemonApi.endpoints.getInfinitePokemon.useInfiniteQuery)
+      .parameter(0)
+      .toEqualTypeOf<string | typeof skipToken>()
+
+    expectTypeOf(pokemonApi.endpoints.getInfinitePokemon.useInfiniteQueryState)
+      .parameter(0)
+      .toEqualTypeOf<string | typeof skipToken>()
+
+    expectTypeOf(
+      pokemonApi.endpoints.getInfinitePokemon.useInfiniteQuerySubscription,
+    )
+      .parameter(0)
+      .toEqualTypeOf<string | typeof skipToken>()
+
+    const slice = createSlice({
+      name: 'pokemon',
+      initialState: {} as { data: Pokemon[] },
+      reducers: {},
+      extraReducers: (builder) => {
+        builder.addMatcher(
+          pokemonApi.endpoints.getInfinitePokemon.matchFulfilled,
+          (state, action) => {
+            expectTypeOf(action.payload).toEqualTypeOf<
+              InfiniteData<Pokemon[], number>
+            >()
+          },
+        )
+      },
+    })
+
     const res = storeRef.store.dispatch(
       pokemonApi.endpoints.getInfinitePokemon.initiate('fire', {}),
     )