import type { CreateSelectorFunction, Selector, createSelector } from 'reselect' import { createDraftSafeSelector } from '../createDraftSafeSelector' import type { EntityState, EntitySelectors, EntityId } from './models' type AnyFunction = (...args: any) => any type AnyCreateSelectorFunction = CreateSelectorFunction< (f: F) => F, (f: F) => F > export interface GetSelectorsOptions { createSelector?: AnyCreateSelectorFunction } export function createSelectorsFactory() { function getSelectors( selectState?: undefined, options?: GetSelectorsOptions, ): EntitySelectors, Id> function getSelectors( selectState: (state: V) => EntityState, options?: GetSelectorsOptions, ): EntitySelectors function getSelectors( selectState?: (state: V) => EntityState, options: GetSelectorsOptions = {}, ): EntitySelectors { const { createSelector = createDraftSafeSelector as AnyCreateSelectorFunction, } = options const selectIds = (state: EntityState) => state.ids const selectEntities = (state: EntityState) => state.entities const selectAll = createSelector( selectIds, selectEntities, (ids, entities): T[] => ids.map((id) => entities[id]!), ) const selectId = (_: unknown, id: Id) => id const selectById = (entities: Record, id: Id) => entities[id] const selectTotal = createSelector(selectIds, (ids) => ids.length) if (!selectState) { return { selectIds, selectEntities, selectAll, selectTotal, selectById: createSelector(selectEntities, selectId, selectById), } } const selectGlobalizedEntities = createSelector( selectState as Selector>, selectEntities, ) return { selectIds: createSelector(selectState, selectIds), selectEntities: selectGlobalizedEntities, selectAll: createSelector(selectState, selectAll), selectTotal: createSelector(selectState, selectTotal), selectById: createSelector( selectGlobalizedEntities, selectId, selectById, ), } } return { getSelectors } }