Skip to content

Commit 6fe387c

Browse files
committed
Fix infinite query lifecycle callback data types (#4818)
1 parent 35af2bf commit 6fe387c

File tree

6 files changed

+114
-24
lines changed

6 files changed

+114
-24
lines changed

packages/toolkit/src/query/core/apiState.ts

+17-20
Original file line numberDiff line numberDiff line change
@@ -30,34 +30,31 @@ export type RefetchConfigOptions = {
3030
refetchOnFocus: boolean
3131
}
3232

33-
export type GetNextPageParamFunction<TPageParam, TQueryFnData> = (
34-
lastPage: TQueryFnData,
35-
allPages: Array<TQueryFnData>,
36-
lastPageParam: TPageParam,
37-
allPageParams: Array<TPageParam>,
38-
) => TPageParam | undefined | null
33+
export type PageParamFunction<DataType, PageParam> = (
34+
firstPage: DataType,
35+
allPages: Array<DataType>,
36+
firstPageParam: PageParam,
37+
allPageParams: Array<PageParam>,
38+
) => PageParam | undefined | null
3939

40-
export type GetPreviousPageParamFunction<TPageParam, TQueryFnData> = (
41-
firstPage: TQueryFnData,
42-
allPages: Array<TQueryFnData>,
43-
firstPageParam: TPageParam,
44-
allPageParams: Array<TPageParam>,
45-
) => TPageParam | undefined | null
46-
47-
export type InfiniteQueryConfigOptions<TQueryFnData, TPageParam> = {
48-
initialPageParam: TPageParam
40+
export type InfiniteQueryConfigOptions<DataType, PageParam> = {
41+
initialPageParam: PageParam
4942
maxPages?: number
5043
/**
5144
* This function can be set to automatically get the previous cursor for infinite queries.
5245
* The result will also be used to determine the value of `hasPreviousPage`.
5346
*/
54-
getPreviousPageParam?: GetPreviousPageParamFunction<TPageParam, TQueryFnData>
55-
getNextPageParam: GetNextPageParamFunction<TPageParam, TQueryFnData>
47+
getPreviousPageParam?: PageParamFunction<DataType, PageParam>
48+
/**
49+
* This function is required to automatically get the next cursor for infinite queries.
50+
* The result will also be used to determine the value of `hasNextPage`.
51+
*/
52+
getNextPageParam: PageParamFunction<DataType, PageParam>
5653
}
5754

58-
export interface InfiniteData<TData, TPageParam> {
59-
pages: Array<TData>
60-
pageParams: Array<TPageParam>
55+
export interface InfiniteData<DataType, PageParam> {
56+
pages: Array<DataType>
57+
pageParams: Array<PageParam>
6158
}
6259

6360
/**

packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ export const buildCacheLifecycleHandler: InternalHandlerBuilder = ({
355355
cacheEntryRemoved,
356356
}
357357

358-
const runningHandler = onCacheEntryAdded(originalArgs, lifecycleApi)
358+
const runningHandler = onCacheEntryAdded(originalArgs, lifecycleApi as any)
359359
// if a `neverResolvedError` was thrown, but not handled in the running handler, do not let it leak out further
360360
Promise.resolve(runningHandler).catch((e) => {
361361
if (e === neverResolvedError) return

packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ export const buildQueryLifecycleHandler: InternalHandlerBuilder = ({
483483
: undefined) as any,
484484
queryFulfilled,
485485
}
486-
onQueryStarted(originalArgs, lifecycleApi)
486+
onQueryStarted(originalArgs, lifecycleApi as any)
487487
}
488488
} else if (isFullfilledThunk(action)) {
489489
const { requestId, baseQueryMeta } = action.meta

packages/toolkit/src/query/endpointDefinitions.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import type {
2121
QueryLifecycleQueryExtraOptions,
2222
} from './core/buildMiddleware/queryLifecycle'
2323
import type {
24+
InfiniteData,
2425
InfiniteQueryConfigOptions,
2526
QuerySubState,
2627
RootState,
@@ -580,13 +581,13 @@ export interface InfiniteQueryExtraOptions<
580581
BaseQuery extends BaseQueryFn,
581582
ReducerPath extends string = string,
582583
> extends CacheLifecycleInfiniteQueryExtraOptions<
583-
ResultType,
584+
InfiniteData<ResultType, PageParam>,
584585
QueryArg,
585586
BaseQuery,
586587
ReducerPath
587588
>,
588589
QueryLifecycleInfiniteQueryExtraOptions<
589-
ResultType,
590+
InfiniteData<ResultType, PageParam>,
590591
QueryArg,
591592
BaseQuery,
592593
ReducerPath

packages/toolkit/src/query/tests/infiniteQueries.test-d.ts

+12
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ describe('Infinite queries', () => {
4141

4242
return `https://example.com/listItems?page=${pageParam}`
4343
},
44+
async onCacheEntryAdded(arg, api) {
45+
const data = await api.cacheDataLoaded
46+
expectTypeOf(data.data).toEqualTypeOf<
47+
InfiniteData<Pokemon[], number>
48+
>()
49+
},
50+
async onQueryStarted(arg, api) {
51+
const data = await api.queryFulfilled
52+
expectTypeOf(data.data).toEqualTypeOf<
53+
InfiniteData<Pokemon[], number>
54+
>()
55+
},
4456
}),
4557
}),
4658
})

packages/toolkit/src/query/tests/infiniteQueries.test.ts

+80
Original file line numberDiff line numberDiff line change
@@ -621,4 +621,84 @@ describe('Infinite queries', () => {
621621
pageParams: [3, 4],
622622
})
623623
})
624+
625+
test('Cache lifecycle methods are called', async () => {
626+
const cacheEntryAddedCallback = vi.fn()
627+
const queryStartedCallback = vi.fn()
628+
629+
const pokemonApi = createApi({
630+
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
631+
endpoints: (builder) => ({
632+
getInfinitePokemonWithLifecycles: builder.infiniteQuery<
633+
Pokemon[],
634+
string,
635+
number
636+
>({
637+
infiniteQueryOptions: {
638+
initialPageParam: 0,
639+
getNextPageParam: (
640+
lastPage,
641+
allPages,
642+
// Page param type should be `number`
643+
lastPageParam,
644+
allPageParams,
645+
) => lastPageParam + 1,
646+
getPreviousPageParam: (
647+
firstPage,
648+
allPages,
649+
firstPageParam,
650+
allPageParams,
651+
) => {
652+
return firstPageParam > 0 ? firstPageParam - 1 : undefined
653+
},
654+
},
655+
query(pageParam) {
656+
return `https://example.com/listItems?page=${pageParam}`
657+
},
658+
async onCacheEntryAdded(arg, api) {
659+
const data = await api.cacheDataLoaded
660+
cacheEntryAddedCallback(arg, data)
661+
},
662+
async onQueryStarted(arg, api) {
663+
const data = await api.queryFulfilled
664+
queryStartedCallback(arg, data)
665+
},
666+
}),
667+
}),
668+
})
669+
670+
const storeRef = setupApiStore(
671+
pokemonApi,
672+
{ ...actionsReducer },
673+
{
674+
withoutTestLifecycles: true,
675+
},
676+
)
677+
678+
const res1 = storeRef.store.dispatch(
679+
pokemonApi.endpoints.getInfinitePokemonWithLifecycles.initiate(
680+
'fire',
681+
{},
682+
),
683+
)
684+
685+
const entry1InitialLoad = await res1
686+
checkResultData(entry1InitialLoad, [[{ id: '0', name: 'Pokemon 0' }]])
687+
688+
expect(cacheEntryAddedCallback).toHaveBeenCalledWith('fire', {
689+
data: {
690+
pages: [[{ id: '0', name: 'Pokemon 0' }]],
691+
pageParams: [0],
692+
},
693+
meta: undefined,
694+
})
695+
696+
expect(queryStartedCallback).toHaveBeenCalledWith('fire', {
697+
data: {
698+
pages: [[{ id: '0', name: 'Pokemon 0' }]],
699+
pageParams: [0],
700+
},
701+
meta: undefined,
702+
})
703+
})
624704
})

0 commit comments

Comments
 (0)