import { isPlainObject } from 'lodash/fp' ; import { Reducer , Store , StoreEnhancer } from 'redux' ; interface Extra < A extends Action > { getActions : ( ) => A [ ] ; clearActions : ( ) => void ; } export default function createStore < S , A extends Action , Ext = { } , StateExt = never > ( reducer , preloadedState ? , enhancer ? ) { if ( ( typeof preloadedState === 'function' && typeof enhancer === 'function' ) || ( typeof enhancer === 'function' && typeof arguments [ 3 ] === 'function' ) ) { throw new Error ( 'It looks like you are passing several store enhancers to ' + 'createStore(). This is not supported. Instead, compose them ' + 'together to a single function.' ) ; } if ( typeof preloadedState === 'function' && typeof enhancer === 'undefined' ) { enhancer = preloadedState as StoreEnhancer < Ext , StateExt > ; preloadedState = undefined ; } if ( typeof enhancer !== 'undefined' ) { if ( typeof enhancer !== 'function' ) { throw new Error ( 'Expected the enhancer to be a function.' ) ; } return enhancer ( createStore as any ) ( reducer , preloadedState as any ) as any ; } if ( typeof reducer !== 'function' ) { throw new Error ( 'Expected the reducer to be a function.' ) ; } const currentReducer = reducer ; let currentState = preloadedState as S ; let currentListeners = [ ] ; let nextListeners = currentListeners ; let dispatchedActions = [ ] ; function ensureCanMutateNextListeners ( ) { if ( nextListeners === currentListeners ) nextListeners = currentListeners . slice ( ) ; } function getState ( ) { return currentState as S ; } function getActions ( ) { return dispatchedActions ; } function subscribe ( listener ) { if ( typeof listener !== 'function' ) { throw new Error ( 'Expected the listener to be a function.' ) ; } let isSubscribed = true ; ensureCanMutateNextListeners ( ) ; nextListeners . push ( listener ) ; return function unsubscribe ( ) { if ( ! isSubscribed ) { return ; } isSubscribed = false ; ensureCanMutateNextListeners ( ) ; const index = nextListeners . indexOf ( listener ) ; nextListeners . splice ( index , 1 ) ; currentListeners = null ; } ; } function dispatch ( action ) { if ( ! isPlainObject ( action ) ) throw new Error ( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) ; if ( typeof action . type === 'undefined' ) throw new Error ( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) ; dispatchedActions . push ( action ) ; currentState = currentReducer ( currentState , action ) ; const listeners = ( currentListeners = nextListeners ) ; for ( let i = 0 ; i < listeners . length ; i ++ ) { const listener = listeners [ i ] ; listener ( ) ; } return action ; } function clearActions ( ) { dispatchedActions = [ ] ; } return { dispatch : dispatch , getState , getActions , subscribe , clearActions , replaceReducer : ( ) => { } , } as unknown as Store < S , A > & Ext & Extra < A > ; }