import { Observable, OperatorFunction } from 'rxjs'; export interface Action { /** Make sure that the `type` is globally unique. */ type: string; value: T; } export declare type ActionStream = Observable>; export declare type ActionReducer = (state: T, action: Action) => T; export declare type ValueReducer = (state: T, value: A) => T; export declare type StreamToState = (action$: ActionStream) => Observable; export declare type ActionHandlerMap = Record>; /** Wrapper for creating `Action`s. */ export interface Actor { type: string; new: (value: T) => Action; } /** Similar to Redux store. */ export interface Store { action$: ActionStream; state$: Observable; getState(): T; dispatch(action: Action): void; destruct(): void; } /** Helper: testing content equality. */ export declare const jsonEqual: (aa: T, bb: T) => boolean; /** Helper: to use in place of `val => !!val`. */ export declare const forceBool: (val: boolean) => boolean; /** Helper: to use in place of `val => +val`. */ export declare const forceNum: (val: number) => number; /** Helper: to use in place of `val => val || orValue`. */ export declare const or_: (orValue: T) => (val: T) => T; /** Helper: to use in place of `val => val || []`. */ export declare const orArray: (val: T[]) => T[]; /** Helper: to use in place of `val => val || null`. */ export declare const orNull: (val: T) => T; /** Helper: to use in place of `val => val || {}`. */ export declare const orObject: (val: T) => T; /** Helper: to use in place of `val => val || 0`. */ export declare const orZero: (val: number) => number; /** Sets `state[key] = value` if not identical and returns as new state. */ export declare const setPropertyIfNotSame: (state: T, key: K, value: T[K]) => T; /** Returns a reducer based on `setPropertyIfNotSame`. */ export declare const redSetPropertyIfNotSame_: (key: K) => ValueReducer; /** Sets `state[key] = value` if not content-equal and returns as new state. */ export declare const setPropertyIfNotEqual: (state: T, key: K, value: T[K]) => T; /** Returns a reducer based on `setPropertyIfNotEqual`. */ export declare const redSetPropertyIfNotEqual_: (key: K) => ValueReducer; /** Reducer for setting `value` as new state. */ export declare const redSet: (state: T, value: T) => T; /** Reducer for merging `value` into `state` as new state. */ export declare const redMerge: (state: T, value: T) => T; /** Returns a reducer which merges the `value` into the `state[key]` as new state. */ export declare const redMergeProperty_: (key: K) => ValueReducer; /** * Returns a reducer built from a map of `Action` handlers. * @example * interface Test { a?: number, b?: string, c?: boolean }; * ... * const red_test = reducers_({ * 'IncrementValueIntoA': (state, val: number) => ({ ...state, a: val + 1 }), * [act_set_b.type]: redSet, * [act_set_c.type]: redSetPropertyIfNotSame_('c'), * }); */ export declare const reducers_: (actionTypeToHandler: Record>) => ActionReducer; /** * Creates an `Actor` with type concatenated from the `type: string[]` parameter. * @example * const STATE = 'ui'; * const STATE_GLOBAL = 'global'; * const set_locale = actor('SET', STATE, STATE_GLOBAL, 'locale'); * ... * const act_set_locale = rxState.act_(set_locale); * ... * act_set_locale('en_US'); */ export declare const actor: (...type: string[]) => Actor; /** * Creates a state Observable emitting new state from scanning the `action$` stream. * @example * interface Test { a?: number, b?: string, c?: boolean }; * const action$ = new Subject>(); * const state$ = toState$(action$, { a: 0, b: '', c: false }, { 'ActMerge': redMerge }); */ export declare const toState$: (action$: ActionStream, init: T, reduce: ActionReducer | Record>) => Observable; /** * Returns a creator for a state Observable emitting new state from scanning the `action$` stream. * @example * interface Test { a?: number, b?: string, c?: boolean }; * const state$_ = toState$_({ a: 0, b: '', c: false }, { 'ActMerge': redMerge }); * ... * const state$ = state$_(action$); */ export declare const toState$_: (init: T, reduce: ActionReducer | Record>) => (action$: ActionStream) => Observable; /** * Assembles a state Observable emitting new state from combining a `base` object or Observable and `parts` values or Observables which relate to the `base` keys. * *WARNING: a nested state from `parts` should not be reduced in the `base` if the `base` is an Observable.* * @example * interface TestNested { a?: number, b?: string, c?: boolean }; * interface Test { a?: TestNested, b?: string }; * const action$ = new Subject>(); * const state_nested$ = toState$(action$, { a: 0, b: 'nested', c: false }, { 'ActMerge': redMerge }); * const state_parent$ = toState$(action$, { a: null, b: 'parent' }, { 'ActSetB': redSetPropertyIfNotSame_('b') }); * const state$ = assemble$(state_parent$, { 'a': state_nested$ }); */ export declare const assemble$: (base: T | Observable, parts?: Partial<{ [K in keyof T]: T[K] | Observable; }>) => Observable; /** * Returns a creator for assembling a state Observable emitting new state from combining a `base` object or Observable and `parts` values * or Observables which relate to the `base` keys. * *WARNING: a nested state from `parts` should not be reduced in the `base` if the `base` is an Observable.* * @example * interface TestNested { a?: number, b?: string, c?: boolean }; * interface Test { a?: TestNested, b?: string }; * const state_nested$_ = toState$_({ a: 0, b: 'nested', c: false }, { 'ActMerge': redMerge }); * const state_parent$_ = toState$_({ a: null, b: 'parent' }, { 'ActSetB': redSetPropertyIfNotSame_('b') }); * const state$_ = assemble$_(state_parent$_, { 'a': state_nested$_ }); * ... * const state$ = state$_(action$); */ export declare const assemble$_: (base: T | StreamToState, parts?: { [K in keyof T]: T[K] | StreamToState; }) => (action$: ActionStream) => Observable; /** * Creates a state Observable (from init object, reducers and nested parts) emitting new state from scanning the `action$` stream. * @example * interface TestNested { c?: number }; * interface Test { a?: TestNested, b?: string }; * const action$ = new Subject>(); * const state_nested$ = initReduceAssemble$(action$, { c: 0 }, { 'ActSetC': redSetPropertyIfNotSame_('c') }); * const state$ = initReduceAssemble$(action$, { a: null, b: 'parent' }, { 'ActSetB': redSetPropertyIfNotSame_('b') }, { a: state_nested$ }); */ export declare const initReduceAssemble$: (action$: ActionStream, init: T, reduce: ActionReducer | Record>, parts?: { [K in keyof T]: T[K] | Observable; }) => Observable; /** * Returns a creator for a state Observable (from init object, reducers and nested parts) emitting new state from scanning the `action$` stream. * @example * interface TestNested { c?: number }; * interface Test { a?: TestNested, b?: string }; * const state_nested$_ = initReduceAssemble$_({ c: 0 }, { 'ActSetC': redSetPropertyIfNotSame_('c') }); * const state$_ = initReduceAssemble$_({ a: null, b: 'parent' }, { 'ActSetB': redSetPropertyIfNotSame_('b') }, { a: state_nested$_ }); * ... * const state$ = state$_(action$); */ export declare const initReduceAssemble$_: (init: T, reduce: ActionReducer | Record>, parts?: { [K in keyof T]: T[K] | StreamToState; }) => (action$: ActionStream) => Observable; declare class StoreImpl implements Store { private readonly createState; constructor(createState: StreamToState); private state; private readonly actionIn$; readonly action$: Observable>; readonly state$: Observable; getState(): T; dispatch(action: Action): void; destruct(): void; } /** * `Store` factory. * @example * const state$_ = assemble$_(...); * ... * const store = createStore(state$_); */ export declare const createStore: (createState: StreamToState) => StoreImpl; /** * Helper function for watching substates. * * @param selector mapper function e.g. `st => st.ui.enabled` * * @example * enabled$ = this.stateService.state$.pipe(watch(st => st.ui.enabled)); */ export declare function watch(selector: (state: T) => R): OperatorFunction; /** * Helper class for wrapping the `Store` by watching and setting the state. * @example * const set_locale = actor('SET', STATE, STATE_GLOBAL, 'locale'); * ... * const state$_ = assemble$_(...); * ... * const store = createStore(state$_); * const rxState = new RxState(store); * const act_set_locale = rxState.act_(set_locale); * ... * rxState.state$.pipe(select(st => st.ui.global.locale)).subscribe(locale => console.log('Locale changed to ' + locale)); * ... * act_set_locale('en_US'); */ export declare class RxState { protected readonly store: Store; constructor(store: Store); private readonly done$; private readonly currentState$; /** Reactive state (use with `.pipe(select(...))` operator) */ readonly state$: Observable; /** Synchronized state value. */ getState: () => S; destroy(): void; /** For debugging/testing. */ dbgGetStore: () => Store; /** * Dispatch an `Action` using an `Actor`, typesafe value and optionally a pre-`transform` function. * @example * const set_locale = actor('SET', STATE, STATE_GLOBAL, 'locale'); * ... * rxState.act(set_locale, newCurrentLocale, or_('en_US')); */ act: (act: Actor, value: T, transform?: (val: T) => T) => void; /** * Create a dispatcher of an `Action` using an `Actor` optionally a pre-`transform` function. * @example * const set_locale = actor('SET', STATE, STATE_GLOBAL, 'locale'); * ... * const act_set_locale = rxState.act_(set_locale, or_('en_US')); * ... * act_set_locale(newCurrentLocale); */ act_: (act: Actor, transform?: (val: T) => T) => (value: T) => void; } export {};