Skip to content

Commit 8f6f018

Browse files
committed
Split the TypedOnQueryStarted type into 2 separate types
1 parent d57a84c commit 8f6f018

File tree

5 files changed

+399
-304
lines changed

5 files changed

+399
-304
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ export type {
3535
MutationLifecycleApi,
3636
QueryLifecycleApi,
3737
ReferenceQueryLifecycle,
38-
TypedOnQueryStarted,
38+
TypedOnQueryStartedForMutationEndpoints,
39+
TypedOnQueryStartedForQueryEndpoints,
3940
} from './queryLifecycle'
4041
export type { SubscriptionSelectors } from './types'
4142

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

Lines changed: 206 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -116,45 +116,6 @@ export type QueryLifecycleQueryExtraOptions<
116116
): Promise<void> | void
117117
}
118118

119-
/**
120-
* @since 2.4.0
121-
* @public
122-
*/
123-
export type TypedOnQueryStarted<
124-
ResultType,
125-
QueryArg,
126-
BaseQuery extends BaseQueryFn,
127-
ReducerPath extends string = string,
128-
DefinitionType extends 'query' | 'mutation' = 'query' | 'mutation',
129-
> = 'query' | 'mutation' extends DefinitionType
130-
? QueryLifecycleMutationExtraOptions<
131-
ResultType,
132-
QueryArg,
133-
BaseQuery,
134-
ReducerPath
135-
>['onQueryStarted'] &
136-
QueryLifecycleQueryExtraOptions<
137-
ResultType,
138-
QueryArg,
139-
BaseQuery,
140-
ReducerPath
141-
>['onQueryStarted']
142-
: 'query' extends DefinitionType
143-
? QueryLifecycleQueryExtraOptions<
144-
ResultType,
145-
QueryArg,
146-
BaseQuery,
147-
ReducerPath
148-
>['onQueryStarted']
149-
: 'mutation' extends DefinitionType
150-
? QueryLifecycleMutationExtraOptions<
151-
ResultType,
152-
QueryArg,
153-
BaseQuery,
154-
ReducerPath
155-
>['onQueryStarted']
156-
: never
157-
158119
export type QueryLifecycleMutationExtraOptions<
159120
ResultType,
160121
QueryArg,
@@ -231,6 +192,212 @@ export type MutationLifecycleApi<
231192
> = MutationBaseLifecycleApi<QueryArg, BaseQuery, ResultType, ReducerPath> &
232193
QueryLifecyclePromises<ResultType, BaseQuery>
233194

195+
/**
196+
* Provides a way to define a strongly-typed version of
197+
* {@linkcode QueryLifecycleQueryExtraOptions.onQueryStarted | onQueryStarted}
198+
* for a specific query.
199+
*
200+
* @example
201+
* <caption>#### __Create and reuse a strongly-typed `onQueryStarted` function__</caption>
202+
*
203+
* ```ts
204+
* import type { TypedOnQueryStartedForQueryEndpoints } from '@reduxjs/toolkit/query'
205+
* import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
206+
*
207+
* type Post = {
208+
* id: number
209+
* title: string
210+
* userId: number
211+
* }
212+
*
213+
* type PostsApiResponse = {
214+
* posts: Post[]
215+
* total: number
216+
* skip: number
217+
* limit: number
218+
* }
219+
*
220+
* type QueryArgument = number | undefined
221+
*
222+
* type BaseQueryFunction = ReturnType<typeof fetchBaseQuery>
223+
*
224+
* const baseApiSlice = createApi({
225+
* baseQuery: fetchBaseQuery({ baseUrl: 'https://dummyjson.com' }),
226+
* reducerPath: 'postsApi',
227+
* tagTypes: ['Posts'],
228+
* endpoints: (builder) => ({
229+
* getPosts: builder.query<PostsApiResponse, void>({
230+
* query: () => `/posts`,
231+
* }),
232+
*
233+
* getPostById: builder.query<Post, QueryArgument>({
234+
* query: (postId) => `/posts/${postId}`,
235+
* }),
236+
* }),
237+
* })
238+
*
239+
* const updatePostOnFulfilled: TypedOnQueryStartedForQueryEndpoints<
240+
* PostsApiResponse,
241+
* QueryArgument,
242+
* BaseQueryFunction,
243+
* 'postsApi'
244+
* > = async (queryArgument, { dispatch, queryFulfilled }) => {
245+
* const result = await queryFulfilled
246+
*
247+
* const { posts } = result.data
248+
*
249+
* // Pre-fill the individual post entries with the results
250+
* // from the list endpoint query
251+
* dispatch(
252+
* baseApiSlice.util.upsertQueryEntries(
253+
* posts.map((post) => ({
254+
* endpointName: 'getPostById',
255+
* arg: post.id,
256+
* value: post,
257+
* })),
258+
* ),
259+
* )
260+
* }
261+
*
262+
* export const extendedApiSlice = baseApiSlice.injectEndpoints({
263+
* endpoints: (builder) => ({
264+
* getPostsByUserId: builder.query<PostsApiResponse, QueryArgument>({
265+
* query: (userId) => `/posts/user/${userId}`,
266+
*
267+
* onQueryStarted: updatePostOnFulfilled,
268+
* }),
269+
* }),
270+
* })
271+
* ```
272+
*
273+
* @template ResultType - The type of the result `data` returned by the query.
274+
* @template QueryArgumentType - The type of the argument passed into the query.
275+
* @template BaseQueryFunctionType - The type of the base query function being used.
276+
* @template ReducerPath - The type representing the `reducerPath` for the API slice.
277+
*
278+
* @since 2.4.0
279+
* @public
280+
*/
281+
export type TypedOnQueryStartedForQueryEndpoints<
282+
ResultType,
283+
QueryArgumentType,
284+
BaseQueryFunctionType extends BaseQueryFn,
285+
ReducerPath extends string = string,
286+
> = QueryLifecycleQueryExtraOptions<
287+
ResultType,
288+
QueryArgumentType,
289+
BaseQueryFunctionType,
290+
ReducerPath
291+
>['onQueryStarted']
292+
293+
/**
294+
* Provides a way to define a strongly-typed version of
295+
* {@linkcode QueryLifecycleMutationExtraOptions.onQueryStarted | onQueryStarted}
296+
* for a specific mutation.
297+
*
298+
* @example
299+
* <caption>#### __Create and reuse a strongly-typed `onQueryStarted` function__</caption>
300+
*
301+
* ```ts
302+
* import type { TypedOnQueryStartedForMutationEndpoints } from '@reduxjs/toolkit/query'
303+
* import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
304+
*
305+
* type Post = {
306+
* id: number
307+
* title: string
308+
* userId: number
309+
* }
310+
*
311+
* type PostsApiResponse = {
312+
* posts: Post[]
313+
* total: number
314+
* skip: number
315+
* limit: number
316+
* }
317+
*
318+
* type QueryArgument = Pick<Post, 'id'> & Partial<Post>
319+
*
320+
* type BaseQueryFunction = ReturnType<typeof fetchBaseQuery>
321+
*
322+
* const baseApiSlice = createApi({
323+
* baseQuery: fetchBaseQuery({ baseUrl: 'https://dummyjson.com' }),
324+
* reducerPath: 'postsApi',
325+
* tagTypes: ['Posts'],
326+
* endpoints: (builder) => ({
327+
* getPosts: builder.query<PostsApiResponse, void>({
328+
* query: () => `/posts`,
329+
* }),
330+
*
331+
* getPostById: builder.query<Post, number>({
332+
* query: (postId) => `/posts/${postId}`,
333+
* }),
334+
* }),
335+
* })
336+
*
337+
* const updatePostOnFulfilled: TypedOnQueryStartedForMutationEndpoints<
338+
* Post,
339+
* QueryArgument,
340+
* BaseQueryFunction,
341+
* 'postsApi'
342+
* > = async ({ id, ...patch }, { dispatch, queryFulfilled }) => {
343+
* const patchCollection = dispatch(
344+
* baseApiSlice.util.updateQueryData('getPostById', id, (draftPost) => {
345+
* Object.assign(draftPost, patch)
346+
* }),
347+
* )
348+
*
349+
* try {
350+
* await queryFulfilled
351+
* } catch {
352+
* patchCollection.undo()
353+
* }
354+
* }
355+
*
356+
* export const extendedApiSlice = baseApiSlice.injectEndpoints({
357+
* endpoints: (builder) => ({
358+
* addPost: builder.mutation<Post, Omit<QueryArgument, 'id'>>({
359+
* query: (body) => ({
360+
* url: `posts/add`,
361+
* method: 'POST',
362+
* body,
363+
* }),
364+
*
365+
* onQueryStarted: updatePostOnFulfilled,
366+
* }),
367+
*
368+
* updatePost: builder.mutation<Post, QueryArgument>({
369+
* query: ({ id, ...patch }) => ({
370+
* url: `post/${id}`,
371+
* method: 'PATCH',
372+
* body: patch,
373+
* }),
374+
*
375+
* onQueryStarted: updatePostOnFulfilled,
376+
* }),
377+
* }),
378+
* })
379+
* ```
380+
*
381+
* @template ResultType - The type of the result `data` returned by the query.
382+
* @template QueryArgumentType - The type of the argument passed into the query.
383+
* @template BaseQueryFunctionType - The type of the base query function being used.
384+
* @template ReducerPath - The type representing the `reducerPath` for the API slice.
385+
*
386+
* @since 2.4.0
387+
* @public
388+
*/
389+
export type TypedOnQueryStartedForMutationEndpoints<
390+
ResultType,
391+
QueryArgumentType,
392+
BaseQueryFunctionType extends BaseQueryFn,
393+
ReducerPath extends string = string,
394+
> = QueryLifecycleMutationExtraOptions<
395+
ResultType,
396+
QueryArgumentType,
397+
BaseQueryFunctionType,
398+
ReducerPath
399+
>['onQueryStarted']
400+
234401
export const buildQueryLifecycleHandler: InternalHandlerBuilder = ({
235402
api,
236403
context,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ export type {
2424
QueryCacheLifecycleApi,
2525
QueryLifecycleApi,
2626
SubscriptionSelectors,
27-
TypedOnQueryStarted,
27+
TypedOnQueryStartedForMutationEndpoints,
28+
TypedOnQueryStartedForQueryEndpoints,
2829
} from './buildMiddleware/index'
2930
export { skipToken } from './buildSelectors'
3031
export type {

packages/toolkit/src/query/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ export { buildCreateApi } from './createApi'
6969
export { _NEVER, fakeBaseQuery } from './fakeBaseQuery'
7070
export { copyWithStructuralSharing } from './utils/copyWithStructuralSharing'
7171
export { createApi, coreModule, coreModuleName } from './core/index'
72-
export type { TypedOnQueryStarted } from './core/index'
72+
export type {
73+
TypedOnQueryStartedForMutationEndpoints,
74+
TypedOnQueryStartedForQueryEndpoints,
75+
} from './core/index'
7376
export type {
7477
ApiEndpointMutation,
7578
ApiEndpointQuery,

0 commit comments

Comments
 (0)