import logger from './logger' ; type callback = ( ) => any ; export default class Store < T > { private _subs : callback [ ] = [ ] ; state : T ; subscribe ( cb ) { const storeName = this . constructor . name ; logger . info ( `subscribe to store ${ storeName }` , this . state ) ; this . _subs . push ( cb ) ; } unsubscribe ( cb ) { const index = this . _subs . indexOf ( cb ) ; if ( index > - 1 ) { const storeName = this . constructor . name ; logger . info ( `unsubscribe from store ${ storeName }` ) ; this . _subs . splice ( index , 1 ) ; } } public setState ( nextState ) { this . state = mergeStates ( nextState , this . state ) ; logger . logState ( this . constructor . name , this . state , 'with' , nextState ) ; this . _subs . forEach ( cb => { try { cb ( ) ; } catch ( err ) { logger . error ( `Store ${ this . constructor . name } failed to notify subscriber` , err ) ; } } ) ; } } function mergeStates < T > ( nextState , prevState ) { if ( isObject ( prevState ) && isObject ( nextState ) ) { return { ... prevState , ... nextState , } ; } return nextState as T ; } function isObject ( obj ) { return ! Array . isArray ( obj ) && typeof obj === 'object' && obj !== null ; }