source: node_modules/reselect/src/createStructuredSelector.ts

main
Last change on this file was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 14.0 KB
Line 
1import { createSelector } from './createSelectorCreator'
2
3import type { CreateSelectorFunction } from './createSelectorCreator'
4import type {
5 InterruptRecursion,
6 ObjectValuesToTuple,
7 OutputSelector,
8 Selector,
9 Simplify,
10 UnknownMemoizer
11} from './types'
12import { assertIsObject } from './utils'
13import type { weakMapMemoize } from './weakMapMemoize'
14
15/**
16 * Represents a mapping of selectors to their return types.
17 *
18 * @template TObject - An object type where each property is a selector function.
19 *
20 * @public
21 */
22export type SelectorResultsMap<TObject extends SelectorsObject> = {
23 [Key in keyof TObject]: ReturnType<TObject[Key]>
24}
25
26/**
27 * Represents a mapping of selectors for each key in a given root state.
28 *
29 * This type is a utility that takes a root state object type and
30 * generates a corresponding set of selectors. Each selector is associated
31 * with a key in the root state, allowing for the selection
32 * of specific parts of the state.
33 *
34 * @template RootState - The type of the root state object.
35 *
36 * @since 5.0.0
37 * @public
38 */
39export type RootStateSelectors<RootState = any> = {
40 [Key in keyof RootState]: Selector<RootState, RootState[Key], []>
41}
42
43/**
44 * @deprecated Please use {@linkcode StructuredSelectorCreator.withTypes createStructuredSelector.withTypes<RootState>()} instead. This type will be removed in the future.
45 * @template RootState - The type of the root state object.
46 *
47 * @since 5.0.0
48 * @public
49 */
50export type TypedStructuredSelectorCreator<RootState = any> =
51 /**
52 * A convenience function that simplifies returning an object
53 * made up of selector results.
54 *
55 * @param inputSelectorsObject - A key value pair consisting of input selectors.
56 * @param selectorCreator - A custom selector creator function. It defaults to `createSelector`.
57 * @returns A memoized structured selector.
58 *
59 * @example
60 * <caption>Modern Use Case</caption>
61 * ```ts
62 * import { createSelector, createStructuredSelector } from 'reselect'
63 *
64 * interface RootState {
65 * todos: {
66 * id: number
67 * completed: boolean
68 * title: string
69 * description: string
70 * }[]
71 * alerts: { id: number; read: boolean }[]
72 * }
73 *
74 * // This:
75 * const structuredSelector = createStructuredSelector(
76 * {
77 * todos: (state: RootState) => state.todos,
78 * alerts: (state: RootState) => state.alerts,
79 * todoById: (state: RootState, id: number) => state.todos[id]
80 * },
81 * createSelector
82 * )
83 *
84 * // Is essentially the same as this:
85 * const selector = createSelector(
86 * [
87 * (state: RootState) => state.todos,
88 * (state: RootState) => state.alerts,
89 * (state: RootState, id: number) => state.todos[id]
90 * ],
91 * (todos, alerts, todoById) => {
92 * return {
93 * todos,
94 * alerts,
95 * todoById
96 * }
97 * }
98 * )
99 * ```
100 *
101 * @example
102 * <caption>In your component:</caption>
103 * ```tsx
104 * import type { RootState } from 'createStructuredSelector/modernUseCase'
105 * import { structuredSelector } from 'createStructuredSelector/modernUseCase'
106 * import type { FC } from 'react'
107 * import { useSelector } from 'react-redux'
108 *
109 * interface Props {
110 * id: number
111 * }
112 *
113 * const MyComponent: FC<Props> = ({ id }) => {
114 * const { todos, alerts, todoById } = useSelector((state: RootState) =>
115 * structuredSelector(state, id)
116 * )
117 *
118 * return (
119 * <div>
120 * Next to do is:
121 * <h2>{todoById.title}</h2>
122 * <p>Description: {todoById.description}</p>
123 * <ul>
124 * <h3>All other to dos:</h3>
125 * {todos.map(todo => (
126 * <li key={todo.id}>{todo.title}</li>
127 * ))}
128 * </ul>
129 * </div>
130 * )
131 * }
132 * ```
133 *
134 * @example
135 * <caption>Simple Use Case</caption>
136 * ```ts
137 * const selectA = state => state.a
138 * const selectB = state => state.b
139 *
140 * // The result function in the following selector
141 * // is simply building an object from the input selectors
142 * const structuredSelector = createSelector(selectA, selectB, (a, b) => ({
143 * a,
144 * b
145 * }))
146 *
147 * const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
148 * ```
149 *
150 * @template InputSelectorsObject - The shape of the input selectors object.
151 * @template MemoizeFunction - The type of the memoize function that is used to create the structured selector. It defaults to `weakMapMemoize`.
152 * @template ArgsMemoizeFunction - The type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `weakMapMemoize`.
153 *
154 * @see {@link https://reselect.js.org/api/createStructuredSelector `createStructuredSelector`}
155 */
156 <
157 InputSelectorsObject extends RootStateSelectors<RootState> = RootStateSelectors<RootState>,
158 MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
159 ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
160 >(
161 inputSelectorsObject: InputSelectorsObject,
162 selectorCreator?: CreateSelectorFunction<
163 MemoizeFunction,
164 ArgsMemoizeFunction
165 >
166 ) => OutputSelector<
167 ObjectValuesToTuple<InputSelectorsObject>,
168 Simplify<SelectorResultsMap<InputSelectorsObject>>,
169 MemoizeFunction,
170 ArgsMemoizeFunction
171 > &
172 InterruptRecursion
173
174/**
175 * Represents an object where each property is a selector function.
176 *
177 * @template StateType - The type of state that all the selectors operate on.
178 *
179 * @public
180 */
181export type SelectorsObject<StateType = any> = Record<
182 string,
183 Selector<StateType>
184>
185
186/**
187 * It provides a way to create structured selectors.
188 * The structured selector can take multiple input selectors
189 * and map their output to an object with specific keys.
190 *
191 * @template StateType - The type of state that the structured selectors created with this structured selector creator will operate on.
192 *
193 * @see {@link https://reselect.js.org/api/createStructuredSelector `createStructuredSelector`}
194 *
195 * @public
196 */
197export interface StructuredSelectorCreator<StateType = any> {
198 /**
199 * A convenience function that simplifies returning an object
200 * made up of selector results.
201 *
202 * @param inputSelectorsObject - A key value pair consisting of input selectors.
203 * @param selectorCreator - A custom selector creator function. It defaults to `createSelector`.
204 * @returns A memoized structured selector.
205 *
206 * @example
207 * <caption>Modern Use Case</caption>
208 * ```ts
209 * import { createSelector, createStructuredSelector } from 'reselect'
210 *
211 * interface RootState {
212 * todos: {
213 * id: number
214 * completed: boolean
215 * title: string
216 * description: string
217 * }[]
218 * alerts: { id: number; read: boolean }[]
219 * }
220 *
221 * // This:
222 * const structuredSelector = createStructuredSelector(
223 * {
224 * todos: (state: RootState) => state.todos,
225 * alerts: (state: RootState) => state.alerts,
226 * todoById: (state: RootState, id: number) => state.todos[id]
227 * },
228 * createSelector
229 * )
230 *
231 * // Is essentially the same as this:
232 * const selector = createSelector(
233 * [
234 * (state: RootState) => state.todos,
235 * (state: RootState) => state.alerts,
236 * (state: RootState, id: number) => state.todos[id]
237 * ],
238 * (todos, alerts, todoById) => {
239 * return {
240 * todos,
241 * alerts,
242 * todoById
243 * }
244 * }
245 * )
246 * ```
247 *
248 * @example
249 * <caption>In your component:</caption>
250 * ```tsx
251 * import type { RootState } from 'createStructuredSelector/modernUseCase'
252 * import { structuredSelector } from 'createStructuredSelector/modernUseCase'
253 * import type { FC } from 'react'
254 * import { useSelector } from 'react-redux'
255 *
256 * interface Props {
257 * id: number
258 * }
259 *
260 * const MyComponent: FC<Props> = ({ id }) => {
261 * const { todos, alerts, todoById } = useSelector((state: RootState) =>
262 * structuredSelector(state, id)
263 * )
264 *
265 * return (
266 * <div>
267 * Next to do is:
268 * <h2>{todoById.title}</h2>
269 * <p>Description: {todoById.description}</p>
270 * <ul>
271 * <h3>All other to dos:</h3>
272 * {todos.map(todo => (
273 * <li key={todo.id}>{todo.title}</li>
274 * ))}
275 * </ul>
276 * </div>
277 * )
278 * }
279 * ```
280 *
281 * @example
282 * <caption>Simple Use Case</caption>
283 * ```ts
284 * const selectA = state => state.a
285 * const selectB = state => state.b
286 *
287 * // The result function in the following selector
288 * // is simply building an object from the input selectors
289 * const structuredSelector = createSelector(selectA, selectB, (a, b) => ({
290 * a,
291 * b
292 * }))
293 *
294 * const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
295 * ```
296 *
297 * @template InputSelectorsObject - The shape of the input selectors object.
298 * @template MemoizeFunction - The type of the memoize function that is used to create the structured selector. It defaults to `weakMapMemoize`.
299 * @template ArgsMemoizeFunction - The type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `weakMapMemoize`.
300 *
301 * @see {@link https://reselect.js.org/api/createStructuredSelector `createStructuredSelector`}
302 */
303 <
304 InputSelectorsObject extends SelectorsObject<StateType>,
305 MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
306 ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
307 >(
308 inputSelectorsObject: InputSelectorsObject,
309 selectorCreator?: CreateSelectorFunction<
310 MemoizeFunction,
311 ArgsMemoizeFunction
312 >
313 ): OutputSelector<
314 ObjectValuesToTuple<InputSelectorsObject>,
315 Simplify<SelectorResultsMap<InputSelectorsObject>>,
316 MemoizeFunction,
317 ArgsMemoizeFunction
318 > &
319 InterruptRecursion
320
321 /**
322 * Creates a "pre-typed" version of
323 * {@linkcode createStructuredSelector createStructuredSelector}
324 * where the `state` type is predefined.
325 *
326 * This allows you to set the `state` type once, eliminating the need to
327 * specify it with every
328 * {@linkcode createStructuredSelector createStructuredSelector} call.
329 *
330 * @returns A pre-typed `createStructuredSelector` with the state type already defined.
331 *
332 * @example
333 * ```ts
334 * import { createStructuredSelector } from 'reselect'
335 *
336 * export interface RootState {
337 * todos: { id: number; completed: boolean }[]
338 * alerts: { id: number; read: boolean }[]
339 * }
340 *
341 * export const createStructuredAppSelector =
342 * createStructuredSelector.withTypes<RootState>()
343 *
344 * const structuredAppSelector = createStructuredAppSelector({
345 * // Type of `state` is set to `RootState`, no need to manually set the type
346 * todos: state => state.todos,
347 * alerts: state => state.alerts,
348 * todoById: (state, id: number) => state.todos[id]
349 * })
350 *
351 * ```
352 * @template OverrideStateType - The specific type of state used by all structured selectors created with this structured selector creator.
353 *
354 * @see {@link https://reselect.js.org/api/createstructuredselector#defining-a-pre-typed-createstructuredselector `createSelector.withTypes`}
355 *
356 * @since 5.1.0
357 */
358 withTypes: <
359 OverrideStateType extends StateType
360 >() => StructuredSelectorCreator<OverrideStateType>
361}
362
363/**
364 * A convenience function that simplifies returning an object
365 * made up of selector results.
366 *
367 * @param inputSelectorsObject - A key value pair consisting of input selectors.
368 * @param selectorCreator - A custom selector creator function. It defaults to `createSelector`.
369 * @returns A memoized structured selector.
370 *
371 * @example
372 * <caption>Modern Use Case</caption>
373 * ```ts
374 * import { createSelector, createStructuredSelector } from 'reselect'
375 *
376 * interface RootState {
377 * todos: {
378 * id: number
379 * completed: boolean
380 * title: string
381 * description: string
382 * }[]
383 * alerts: { id: number; read: boolean }[]
384 * }
385 *
386 * // This:
387 * const structuredSelector = createStructuredSelector(
388 * {
389 * todos: (state: RootState) => state.todos,
390 * alerts: (state: RootState) => state.alerts,
391 * todoById: (state: RootState, id: number) => state.todos[id]
392 * },
393 * createSelector
394 * )
395 *
396 * // Is essentially the same as this:
397 * const selector = createSelector(
398 * [
399 * (state: RootState) => state.todos,
400 * (state: RootState) => state.alerts,
401 * (state: RootState, id: number) => state.todos[id]
402 * ],
403 * (todos, alerts, todoById) => {
404 * return {
405 * todos,
406 * alerts,
407 * todoById
408 * }
409 * }
410 * )
411 * ```
412 *
413 * @see {@link https://reselect.js.org/api/createStructuredSelector `createStructuredSelector`}
414 *
415 * @public
416 */
417export const createStructuredSelector: StructuredSelectorCreator =
418 Object.assign(
419 <
420 InputSelectorsObject extends SelectorsObject,
421 MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
422 ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
423 >(
424 inputSelectorsObject: InputSelectorsObject,
425 selectorCreator: CreateSelectorFunction<
426 MemoizeFunction,
427 ArgsMemoizeFunction
428 > = createSelector as CreateSelectorFunction<
429 MemoizeFunction,
430 ArgsMemoizeFunction
431 >
432 ) => {
433 assertIsObject(
434 inputSelectorsObject,
435 'createStructuredSelector expects first argument to be an object ' +
436 `where each property is a selector, instead received a ${typeof inputSelectorsObject}`
437 )
438 const inputSelectorKeys = Object.keys(inputSelectorsObject)
439 const dependencies = inputSelectorKeys.map(
440 key => inputSelectorsObject[key]
441 )
442 const structuredSelector = selectorCreator(
443 dependencies,
444 (...inputSelectorResults: any[]) => {
445 return inputSelectorResults.reduce((composition, value, index) => {
446 composition[inputSelectorKeys[index]] = value
447 return composition
448 }, {})
449 }
450 )
451 return structuredSelector
452 },
453 { withTypes: () => createStructuredSelector }
454 ) as StructuredSelectorCreator
Note: See TracBrowser for help on using the repository browser.