@@ -332,6 +332,119 @@ export type QueryStateSelector<
332
332
D extends QueryDefinition < any , any , any , any > ,
333
333
> = ( state : UseQueryStateDefaultResult < D > ) => R
334
334
335
+ /**
336
+ * Provides a way to define a strongly-typed version of
337
+ * {@linkcode QueryStateSelector} for use with a specific query.
338
+ * This is useful for scenarios where you want to create a "pre-typed"
339
+ * {@linkcode UseQueryStateOptions.selectFromResult | selectFromResult}
340
+ * function.
341
+ *
342
+ * @example
343
+ * <caption>#### __Create a strongly-typed `selectFromResult` selector function__</caption>
344
+ *
345
+ * ```tsx
346
+ * import type { TypedQueryStateSelector } from '@reduxjs/toolkit/query/react'
347
+ * import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
348
+ *
349
+ * type Post = {
350
+ * id: number
351
+ * title: string
352
+ * }
353
+ *
354
+ * type PostsApiResponse = {
355
+ * posts: Post[]
356
+ * total: number
357
+ * skip: number
358
+ * limit: number
359
+ * }
360
+ *
361
+ * type QueryArgument = number | undefined
362
+ *
363
+ * type BaseQueryFunction = ReturnType<typeof fetchBaseQuery>
364
+ *
365
+ * type SelectedResult = Pick<PostsApiResponse, 'posts'>
366
+ *
367
+ * const postsApiSlice = createApi({
368
+ * baseQuery: fetchBaseQuery({ baseUrl: 'https://dummyjson.com/posts' }),
369
+ * reducerPath: 'postsApi',
370
+ * tagTypes: ['Posts'],
371
+ * endpoints: (build) => ({
372
+ * getPosts: build.query<PostsApiResponse, QueryArgument>({
373
+ * query: (limit = 5) => `?limit=${limit}&select=title`,
374
+ * }),
375
+ * }),
376
+ * })
377
+ *
378
+ * const { useGetPostsQuery } = postsApiSlice
379
+ *
380
+ * function PostById({ id }: { id: number }) {
381
+ * const { post } = useGetPostsQuery(undefined, {
382
+ * selectFromResult: (state) => ({
383
+ * post: state.data?.posts.find((post) => post.id === id),
384
+ * }),
385
+ * })
386
+ *
387
+ * return <li>{post?.title}</li>
388
+ * }
389
+ *
390
+ * const EMPTY_ARRAY: Post[] = []
391
+ *
392
+ * const typedSelectFromResult: TypedQueryStateSelector<
393
+ * PostsApiResponse,
394
+ * QueryArgument,
395
+ * BaseQueryFunction,
396
+ * SelectedResult
397
+ * > = (state) => ({ posts: state.data?.posts ?? EMPTY_ARRAY })
398
+ *
399
+ * function PostsList() {
400
+ * const { posts } = useGetPostsQuery(undefined, {
401
+ * selectFromResult: typedSelectFromResult,
402
+ * })
403
+ *
404
+ * return (
405
+ * <div>
406
+ * <ul>
407
+ * {posts.map((post) => (
408
+ * <PostById key={post.id} id={post.id} />
409
+ * ))}
410
+ * </ul>
411
+ * </div>
412
+ * )
413
+ * }
414
+ * ```
415
+ *
416
+ * @template ResultType - The type of the result `data` returned by the query.
417
+ * @template QueryArgumentType - The type of the argument passed into the query.
418
+ * @template BaseQueryFunctionType - The type of the base query function being used.
419
+ * @template SelectedResultType - The type of the selected result returned by the __`selectFromResult`__ function.
420
+ *
421
+ * @since 2.7.9
422
+ * @public
423
+ */
424
+ export type TypedQueryStateSelector <
425
+ ResultType ,
426
+ QueryArgumentType ,
427
+ BaseQueryFunctionType extends BaseQueryFn ,
428
+ SelectedResultType extends Record < string , any > = UseQueryStateDefaultResult <
429
+ QueryDefinition <
430
+ QueryArgumentType ,
431
+ BaseQueryFunctionType ,
432
+ string ,
433
+ ResultType ,
434
+ string
435
+ >
436
+ > ,
437
+ > = QueryStateSelector <
438
+ SelectedResultType ,
439
+ QueryDefinition <
440
+ QueryArgumentType ,
441
+ BaseQueryFunctionType ,
442
+ string ,
443
+ ResultType ,
444
+ string
445
+ >
446
+ >
447
+
335
448
/**
336
449
* A React hook that reads the request status and cached data from the Redux store. The component will re-render as the loading status changes and the data becomes available.
337
450
*
0 commit comments