@@ -332,6 +332,119 @@ export type QueryStateSelector<
332332 D extends QueryDefinition < any , any , any , any > ,
333333> = ( state : UseQueryStateDefaultResult < D > ) => R
334334
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+
335448/**
336449 * 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.
337450 *
0 commit comments