1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- import { Subject, BehaviorSubject } from "rxjs"
- import { map } from "rxjs/operators"
- import assign from "lodash/assign"
- import clone from "lodash/clone"
- type dispatcherFunc<StoreType> = (
- currentVal: StoreType,
- payload: any
- ) => Partial<StoreType>
- /**
- * Defines a dispatcher.
- *
- * This function exists to provide better typing for dispatch function.
- * As you can see, its pretty much an identity function.
- */
- export const defineDispatchers = <StoreType, T>(
- // eslint-disable-next-line no-unused-vars
- dispatchers: { [_ in keyof T]: dispatcherFunc<StoreType> }
- ) => dispatchers
- type Dispatch<
- StoreType,
- DispatchersType extends Record<string, dispatcherFunc<StoreType>>
- > = {
- dispatcher: keyof DispatchersType
- payload: any
- }
- export default class DispatchingStore<
- StoreType,
- DispatchersType extends Record<string, dispatcherFunc<StoreType>>
- > {
- #state$: BehaviorSubject<StoreType>
- #dispatchers: DispatchersType
- #dispatches$: Subject<Dispatch<StoreType, DispatchersType>> = new Subject()
- constructor(initialValue: StoreType, dispatchers: DispatchersType) {
- this.#state$ = new BehaviorSubject(initialValue)
- this.#dispatchers = dispatchers
- this.#dispatches$
- .pipe(
- map(({ dispatcher, payload }) =>
- this.#dispatchers[dispatcher](this.value, payload)
- )
- )
- .subscribe((val) => {
- const data = clone(this.value)
- assign(data, val)
- this.#state$.next(data)
- })
- }
- get subject$() {
- return this.#state$
- }
- get value() {
- return this.subject$.value
- }
- get dispatches$() {
- return this.#dispatches$
- }
- dispatch({ dispatcher, payload }: Dispatch<StoreType, DispatchersType>) {
- if (!this.#dispatchers[dispatcher])
- throw new Error(`Undefined dispatch type '${dispatcher}'`)
- this.#dispatches$.next({ dispatcher, payload })
- }
- }
|