All files / src/redux/selectors index.ts

0% Statements 0/96
100% Branches 0/0
0% Functions 0/1
0% Lines 0/96

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97                                                                                                                                                                                                 
/**
 * Redux Selector Utilities
 *
 * Centralized selector utilities for memoization and type safety.
 * Uses createSelector from Redux Toolkit for efficient memoization.
 */

import { createSelector } from '@reduxjs/toolkit';
import type { RootState } from '../store';

// Re-export createSelector for consistent imports
export { createSelector };

/**
 * Type helper for selector creation
 * Ensures proper typing for selector functions
 */
export type AppSelector<T> = (state: RootState) => T;

/**
 * Type helper for parameterized selectors
 */
export type ParameterizedSelector<TParams, TResult> = (
  state: RootState,
  params: TParams
) => TResult;

/**
 * Create a typed selector with proper RootState inference
 *
 * @example
 * const selectUserName = createAppSelector(state => state.user.name);
 */
export function createAppSelector<T>(selector: AppSelector<T>): AppSelector<T> {
  return selector;
}

/**
 * Create a parameterized selector factory
 * Useful for selectors that need runtime parameters like IDs
 *
 * @example
 * const selectItemById = createParameterizedSelector(
 *   (id: number) => createSelector(
 *     [selectAllItems],
 *     (items) => items.find(item => item.id === id)
 *   )
 * );
 */
export function createParameterizedSelector<TParams, TResult>(
  selectorFactory: (params: TParams) => AppSelector<TResult>
): (params: TParams) => AppSelector<TResult> {
  const cache = new Map<string, AppSelector<TResult>>();

  return (params: TParams) => {
    const key = JSON.stringify(params);
    if (!cache.has(key)) {
      cache.set(key, selectorFactory(params));
    }
    return cache.get(key)!;
  };
}

/**
 * Combine multiple selectors into one
 * Useful for components that need data from multiple slices
 *
 * @example
 * const selectCheckoutData = combineSelectors(
 *   selectCartItems,
 *   selectCurrentUser,
 *   (cart, user) => ({ cart, user })
 * );
 */
export function combineSelectors<R1, R2, Result>(
  selector1: AppSelector<R1>,
  selector2: AppSelector<R2>,
  combiner: (r1: R1, r2: R2) => Result
): AppSelector<Result>;
export function combineSelectors<R1, R2, R3, Result>(
  selector1: AppSelector<R1>,
  selector2: AppSelector<R2>,
  selector3: AppSelector<R3>,
  combiner: (r1: R1, r2: R2, r3: R3) => Result
): AppSelector<Result>;
export function combineSelectors(
  ...args: [...AppSelector<unknown>[], (...results: unknown[]) => unknown]
): AppSelector<unknown> {
  const combiner = args.pop() as (...results: unknown[]) => unknown;
  const selectors = args as AppSelector<unknown>[];
  return createSelector(selectors, combiner);
}

// Re-export all domain selectors
export * from './cartSelectors';
export * from './wishlistSelectors';