import { IRef, IStore, StoreEvent } from "./model"; import { IStoreOptions, StoreFsm } from "./store-fsm"; import { sub } from "./sub"; export type IStoresMap = { [key: string]: IStore, }; type RefValueType> = V extends IRef ? T : never; export type ComposedState = { [key in keyof V]: RefValueType; }; export type ComposedStoreOf = IStore>; export class ComposedStore implements ComposedStoreOf { private readonly ref: IRef>; private readonly fsm: StoreFsm>; constructor( private readonly stores: M, opts?: IStoreOptions>, ) { this.ref = sub(() => { const v = {} as ComposedState; for (const key of Object.keys(this.stores)) { // NOTE: we go tthe key from the object, so it must be valid v[key as keyof M] = this.stores[key].deref(); } return v; })(); this.fsm = new StoreFsm( this, () => this.getSnapshot(), newState => this.loadSnapshot(newState), opts, ); } dispatch(f: StoreEvent>) { this.fsm.dispatch(f); } dispatchSync(f: StoreEvent>) { this.fsm.dispatchSync(f); } getSnapshot(): ComposedState { const v = {} as ComposedState; for (const key of Object.keys(this.stores)) { // NOTE: we go tthe key from the object, so it must be valid v[key as keyof M] = this.stores[key].getSnapshot(); } return v; } loadSnapshot(snapshot: ComposedState): void { for (const key of Object.keys(this.stores)) { this.stores[key].loadSnapshot(snapshot[key]); } } deref(): ComposedState { return this.ref.deref(); } }