storeon
Version:
Tiny (167 bytes) event-based Redux-like state manager for React and Preact
102 lines (91 loc) • 2.77 kB
TypeScript
type DataTypes<Map, Key extends keyof Map> = Map extends never
? [any?]
: Map[Key] extends never | undefined
? [never?]
: [Map[Key]]
/**
* Store with application state and event listeners.
*/
export interface StoreonStore<State = unknown, Events = any> {
/**
* Add event listener.
*
* @param event The event name.
* @param handler The event listener.
* @returns The function to remove listener.
*/
on<Event extends keyof (Events & StoreonEvents<State, Events>)>(
event: Event,
handler: createStoreon.EventHandler<State, Events, Event>
): () => 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<Events & createStoreon.DispatchableEvents<State>>
}
export type StoreonModule<State, Events = any> = (
store: StoreonStore<State, Events>
) => void
export interface StoreonEvents<State, Events = any>
extends createStoreon.DispatchableEvents<State> {
'@dispatch': createStoreon.DispatchEvent<
State,
Events & createStoreon.DispatchableEvents<State>
>
}
export type StoreonDispatch<Events> = (<Event extends keyof Events>(
event: Event,
...data: DataTypes<Partial<Events>, Event>
) => void) & { ___events: Events }
export namespace createStoreon {
export type DispatchEvent<
State,
Events,
Event extends keyof Events = keyof Events
> = [Event, Events[Event], EventHandler<State, Events, Event>[]]
export type EventHandler<
State,
Events,
Event extends keyof (Events & StoreonEvents<State, Events>)
> = (
state: State extends object ? Readonly<State> : State,
data: (Events & StoreonEvents<State, Events>)[Event]
) => Partial<State> | Promise<void> | null | void
export interface DispatchableEvents<State> {
'@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<State, Events = any> (
modules: (StoreonModule<State, Events> | false)[]
): StoreonStore<State, Events>