import type { Selector , GetParamsFromSelectors , OutputSelector , SelectorArray , SelectorResultArray , DropFirst , MergeParameters , Expand , ObjValueTuple , Head , Tail } from './types' ; export type { Selector , GetParamsFromSelectors , OutputSelector , EqualityFn , SelectorArray , SelectorResultArray , ParametricSelector , OutputParametricSelector , OutputSelectorFields } from './types' ; import { defaultMemoize , defaultEqualityCheck , DefaultMemoizeOptions } from './defaultMemoize' ; export { defaultMemoize , defaultEqualityCheck } ; export type { DefaultMemoizeOptions } ; function getDependencies ( funcs ) { const dependencies = Array . isArray ( funcs [ 0 ] ) ? funcs [ 0 ] : funcs ; if ( ! dependencies . every ( dep => typeof dep === 'function' ) ) { const dependencyTypes = dependencies . map ( dep => typeof dep === 'function' ? `function ${ dep . name || 'unnamed' }()` : typeof dep ) . join ( ', ' ) ; throw new Error ( `createSelector expects all input-selectors to be functions, but received the following types: [${ dependencyTypes }]` ) ; } return dependencies as SelectorArray ; } export function createSelectorCreator < F extends ( ... args : unknown [ ] ) => unknown , MemoizeFunction extends ( func : F , ... options : any [ ] ) => F , MemoizeOptions extends unknown [ ] = DropFirst < Parameters < MemoizeFunction > > > ( memoize , ... memoizeOptionsFromArgs ) { const createSelector = ( ... funcs ) => { let recomputations = 0 ; let lastResult ; let directlyPassedOptions = { memoizeOptions : undefined } ; let resultFunc = funcs . pop ( ) ; if ( typeof resultFunc === 'object' ) { directlyPassedOptions = resultFunc as any ; resultFunc = funcs . pop ( ) ; } if ( typeof resultFunc !== 'function' ) { throw new Error ( `createSelector expects an output function after the inputs, but received: [${ typeof resultFunc }]` ) ; } const { memoizeOptions = memoizeOptionsFromArgs } = directlyPassedOptions ; const finalMemoizeOptions = Array . isArray ( memoizeOptions ) ? memoizeOptions : ( [ memoizeOptions ] as MemoizeOptions ) ; const dependencies = getDependencies ( funcs ) ; const memoizedResultFunc = memoize ( function ( ) { recomputations ++ ; return resultFunc ! . apply ( null , arguments ) ; } as F , ... finalMemoizeOptions ) ; const selector = memoize ( function ( ) { const params = [ ] ; const length = dependencies . length ; for ( let i = 0 ; i < length ; i ++ ) { params . push ( dependencies [ i ] . apply ( null , arguments ) ) ; } lastResult = memoizedResultFunc . apply ( null , params ) ; return lastResult ; } as F ) ; Object . assign ( selector , { resultFunc , memoizedResultFunc , dependencies , lastResult : ( ) => lastResult , recomputations : ( ) => recomputations , resetRecomputations : ( ) => ( recomputations = 0 ) } ) ; return selector ; } ; return createSelector as CreateSelectorFunction < F , MemoizeFunction , MemoizeOptions > ; } export interface CreateSelectorOptions < MemoizeOptions extends unknown [ ] > { memoizeOptions : MemoizeOptions [ 0 ] | MemoizeOptions ; } /**
 * An instance of createSelector, customized with a given memoize implementation
 */ export interface CreateSelectorFunction < F extends ( ... args : unknown [ ] ) => unknown , MemoizeFunction extends ( func : F , ... options : any [ ] ) => F , MemoizeOptions extends unknown [ ] = DropFirst < Parameters < MemoizeFunction > > , Keys = Expand < Pick < ReturnType < MemoizeFunction > , keyof ReturnType < MemoizeFunction > > > > { /** Input selectors as separate inline arguments */ < Selectors extends SelectorArray , Result > ( ... items ) : OutputSelector < Selectors , Result , ( ... args : SelectorResultArray < Selectors > ) => Result & Keys , GetParamsFromSelectors < Selectors > > & Keys ; /** Input selectors as separate inline arguments with memoizeOptions passed */ < Selectors extends SelectorArray , Result > ( ... items ) : OutputSelector < Selectors , Result , ( ( ... args : SelectorResultArray < Selectors > ) => Result ) & Keys , GetParamsFromSelectors < Selectors > > & Keys ; /** Input selectors as a separate array */ < Selectors extends SelectorArray , Result > ( selectors , combiner , options ? ) : OutputSelector < Selectors , Result , ( ... args : SelectorResultArray < Selectors > ) => Result & Keys , GetParamsFromSelectors < Selectors > > & Keys ; } export const createSelector = createSelectorCreator ( defaultMemoize ) ; type SelectorsObject = { [ key ] : ( ... args : any [ ] ) => any ; } ; export interface StructuredSelectorCreator { < SelectorMap extends SelectorsObject , SelectorParams = MergeParameters < ObjValueTuple < SelectorMap > > > ( selectorMap , selectorCreator ? ) : ( state : Head < SelectorParams > , ... params : Tail < SelectorParams > ) => { [ Key in keyof SelectorMap ] : ReturnType < SelectorMap [ Key ] > ; } ; < State , Result = State > ( selectors , selectorCreator ? ) : Selector < State , Result , never > ; } export const createStructuredSelector = ( ( selectors , selectorCreator = createSelector ) => { if ( typeof selectors !== 'object' ) { throw new Error ( 'createStructuredSelector expects first argument to be an object ' + `where each property is a selector, instead received a ${ typeof selectors }` ) ; } const objectKeys = Object . keys ( selectors ) ; const resultSelector = selectorCreator ( objectKeys . map ( key => selectors [ key ] ) , ( ... values ) => { return values . reduce ( ( composition , value , index ) => { composition [ objectKeys [ index ] ] = value ; return composition ; } , { } ) ; } ) ; return resultSelector ; } ) as unknown as StructuredSelectorCreator ;