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