import { Action, ActionCreator, AnyAction, StoreEnhancer, Store } from 'redux'; export type UnknownAction = AnyAction | never; export interface StoreCreator { ( reducer: LoopReducer, preloadedState: S | undefined, enhancer: StoreEnhancer ): Store; } type WithDefaultActionHandling = | T | Action<'@@REDUX_LOOP/ENFORCE_DEFAULT_HANDLING'>; export type Loop = [S, CmdType]; export interface LoopReducer { (state: S | undefined, action: WithDefaultActionHandling, ...args: any[]): | S | Loop; } export interface LoopReducerWithDefinedState { (state: S, action: WithDefaultActionHandling, ...args: any[]): S | Loop; } export interface LiftedLoopReducer { ( state: S | undefined, action: WithDefaultActionHandling, ...args: any[] ): Loop; } export type CmdSimulation = { result: any; success: boolean; }; export interface MultiCmdSimulation { [index: number]: CmdSimulation | MultiCmdSimulation; } export interface NoneCmd { readonly type: 'NONE'; simulate(): null; } export interface ListCmd { readonly type: 'LIST'; readonly cmds: CmdType[]; readonly sequence?: boolean; readonly batch?: boolean; simulate(simulations: MultiCmdSimulation): AnyAction[]; } export interface ActionCmd { readonly type: 'ACTION'; readonly actionToDispatch: A; simulate(): A; } export interface SetTimeoutCmd { readonly type: 'SET_TIMEOUT'; readonly nestedCmd: CmdType; readonly delayMs: number; readonly scheduledActionCreator?: (timerId: number) => A; simulate(timerId: number, nestedSimulation?: CmdSimulation | MultiCmdSimulation): A[] | A | null } export interface SetIntervalCmd { readonly type: 'SET_INTERVAL'; readonly nestedCmd: CmdType; readonly delayMs: number; readonly scheduledActionCreator?: (timerId: number) => A; simulate(timerId: number, nestedSimulation?: CmdSimulation | MultiCmdSimulation): A[] | A | null } export interface MapCmd { readonly type: 'MAP'; readonly tagger: ActionCreator; readonly nestedCmd: CmdType; readonly args: any[]; simulate(simulations?: CmdSimulation | MultiCmdSimulation): A[] | A | null; } export interface RunCmd< SuccessAction extends Action = never, FailAction extends Action = never > { readonly type: 'RUN'; readonly func: (...args: any[]) => any; readonly args?: any[]; readonly failActionCreator?: ActionCreator; readonly successActionCreator?: ActionCreator; readonly forceSync?: boolean; simulate(simulation: CmdSimulation): SuccessAction | FailAction; } export type CmdType = | ActionCmd | SetTimeoutCmd | SetIntervalCmd | ListCmd | MapCmd | NoneCmd | RunCmd; export interface LoopConfig { readonly DONT_LOG_ERRORS_ON_HANDLED_FAILURES?: boolean; readonly ENABLE_THUNK_MIGRATION?: boolean; } export function install(config?: LoopConfig): StoreEnhancer; export function loop(state: S, cmd: CmdType): Loop; export namespace Cmd { export const dispatch: unique symbol; export const getState: unique symbol; export const none: NoneCmd; export type Dispatch = (a: A) => Promise; export type GetState = () => S; export function action(action: A): ActionCmd; export type ListOptions = { batch?: boolean; sequence?: boolean; testInvariants?: boolean; }; export function list(cmds: CmdType[], options?: ListOptions): ListCmd; export function clearTimeout(timerId: number): RunCmd; export function clearInterval(timerId: number): RunCmd; export function setTimeout( cmd: CmdType, delayMs: number, options?: { scheduledActionCreator?: (timerId: number) => A; }, ): SetTimeoutCmd; export function setInterval( cmd: CmdType, delayMs: number, options?: { scheduledActionCreator?: (timerId: number) => A; }, ): SetIntervalCmd; export function map( cmd: CmdType, tagger: (subAction: B) => A, args?: any[] ): MapCmd; // Allow the use of special dispatch | getState symbols type ArgOrSymbol = { [K in keyof T]: T[K] extends GetState ? typeof getState : T[K] extends Dispatch ? typeof dispatch : T[K]; }; type RunFunc = (...args: any[]) => Promise | any; export type PromiseResult = T extends Promise ? U : T; export type RunOptions< Func extends RunFunc, SuccessAction extends Action = never, FailAction extends Action = never, FailReason = unknown > = { args?: ArgOrSymbol>; forceSync?: boolean; testInvariants?: boolean; successActionCreator: ( value: PromiseResult> ) => SuccessAction; failActionCreator: (error: FailReason) => FailAction; }; export function run( f: Func, options?: Omit< RunOptions, 'successActionCreator' | 'failActionCreator' > ): RunCmd; export function run( f: Func, options: Omit, 'failActionCreator'> ): RunCmd; export function run< Func extends RunFunc, FailAction extends Action, FailReason = unknown >( f: Func, options: Omit< RunOptions, 'successActionCreator' > ): RunCmd; export function run< Func extends RunFunc, SuccessAction extends Action, FailAction extends Action, FailReason = unknown >( f: Func, options: RunOptions ): RunCmd; } export type ReducersMapObject = { [K in keyof S]: LoopReducer; }; export function combineReducers( reducers: ReducersMapObject ): LiftedLoopReducer; export function mergeChildReducers( parentResult: S | Loop, action: AnyAction, childMap: ReducersMapObject ): Loop; // eslint-disable-next-line camelcase export function DEPRECATED_mergeChildReducers( parentResult: S | Loop, action: AnyAction, childMap: ReducersMapObject ): Loop; export function reduceReducers( initialReducer: LoopReducer, ...reducers: Array> ): LiftedLoopReducer; export function reduceReducers( initialReducer: LoopReducer, ...reducers: Array> ): LiftedLoopReducer; export function liftState(state: S | Loop): Loop; export function isLoop(test: any): boolean; export function getModel(loop: S | Loop): S; export function getCmd(a: any): CmdType | null; export type HandlerReturn = S | Loop;