type DataTypes = Map extends never ? [any?] : Map[Key] extends never | undefined ? [never?] : [Map[Key]] /** * Store with application state and event listeners. */ export interface StoreonStore { /** * Add event listener. * * @param event The event name. * @param handler The event listener. * @returns The function to remove listener. */ on)>( event: Event, handler: createStoreon.EventHandler ): () => void /** * Return current state. You can use this method only to read state. * Any state changes should be in event listeners. * * @returns The current state. */ get(): State /** * Emit event. * * @param event The event name. * @param data Any additional data for the event. * @returns The current state. */ dispatch: StoreonDispatch> } export type StoreonModule = ( store: StoreonStore ) => void export interface StoreonEvents extends createStoreon.DispatchableEvents { '@dispatch': createStoreon.DispatchEvent< State, Events & createStoreon.DispatchableEvents > } export type StoreonDispatch = (( event: Event, ...data: DataTypes, Event> ) => void) & { ___events: Events } export namespace createStoreon { export type DispatchEvent< State, Events, Event extends keyof Events = keyof Events > = [Event, Events[Event], EventHandler[]] export type EventHandler< State, Events, Event extends keyof (Events & StoreonEvents) > = ( state: State extends object ? Readonly : State, data: (Events & StoreonEvents)[Event], store: StoreonStore ) => Partial | Promise | null | void export interface DispatchableEvents { '@init': never '@changed': State } } /** * Initialize new store and apply all modules to the store. * * ```js * import { createStoreon } from 'storeon' * let increment = store => { * store.on('@init', () => ({ count: 0 })) * store.on('inc', ({ count }) => ({ count: count + 1 })) * } * const store = createStoreon([increment]) * store.get().count //=> 0 * store.dispatch('inc') * store.get().count //=> 1 * ``` * * @param modules Functions which will set initial state define reducer * and subscribe to all system events. * @returns The new store. */ export function createStoreon( modules: (StoreonModule | false)[] ): StoreonStore