import { Action } from "redux";
import { Draft } from "immer";
import { Cmd, Loop } from "redux-loop";
/**
 * Use `unImmer()` to safely pass objects from reducers to effects.
 *
 * @param obj Any object
 * @returns any
 */
export declare const unImmer: (obj: any) => any;
declare type DeepReadonly<T> = T extends (infer R)[] ? DeepReadonlyArray<R> : T extends Function ? T : T extends object ? DeepReadonlyObject<T> : T;
interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {
}
declare type DeepReadonlyObject<T> = {
    readonly [P in keyof T]: DeepReadonly<T[P]>;
};
export interface AnyAction extends Action {
    [extraProps: string]: any;
}
export interface TypedActionCreator<Type extends string> {
    (...args: any[]): Action<Type>;
    type: Type;
}
declare type MyCaseReducer<S = any, A extends Action = AnyAction> = (state: DeepReadonly<S>, action: A) => DeepReadonly<S> | Loop<DeepReadonly<S>>;
declare type LoopCaseReducer<S = any, A extends Action = AnyAction> = (state: Draft<S>, action: A, cmd: CMD) => void | S;
export interface CMD {
    run: typeof Cmd.run;
    action: typeof Cmd.action;
    list: typeof Cmd.list;
    map: typeof Cmd.map;
    setTimeout: typeof Cmd.setTimeout;
    setInterval: typeof Cmd.setInterval;
    clearTimeout: typeof Cmd.clearTimeout;
    clearInterval: typeof Cmd.clearInterval;
}
export interface ActionReducerMapBuilder<State> {
    addNoImmerCase<ActionCreator extends TypedActionCreator<string>>(actionCreator: ActionCreator, reducer: MyCaseReducer<State, ReturnType<ActionCreator>>): ActionReducerMapBuilder<State>;
    addNoImmerCase<Type extends string, A extends Action<Type>>(type: Type, reducer: MyCaseReducer<State, A>): ActionReducerMapBuilder<State>;
    addCase<ActionCreator extends TypedActionCreator<string>>(actionCreator: ActionCreator, reducer: LoopCaseReducer<State, ReturnType<ActionCreator>>): ActionReducerMapBuilder<State>;
    addCase<Type extends string, A extends Action<Type>>(type: Type, reducer: LoopCaseReducer<State, A>): ActionReducerMapBuilder<State>;
}
declare type CaseReducerValue<State> = {
    reducer?: MyCaseReducer<State>;
    loopReducer?: LoopCaseReducer<State>;
};
declare type CaseReducers<State> = {
    [key: string]: CaseReducerValue<State>[];
};
/**
 * A slimmed down version of RTK's builder. See comments below in createReducer() for more information.
 */
export declare function executeReducerBuilderCallback<S>(builderCallback: (builder: ActionReducerMapBuilder<S>) => void): CaseReducers<S>;
export declare type Reducer<S = any, A extends Action = AnyAction> = (state: S | undefined, action: A) => S;
export declare type CreateReducerHook = <S>(previousState: S, nextState: S, action: AnyAction) => void;
/**
 * This requires that redux-loops middleware has been installed in the store.
 *
 * This is a forked version of the custom createReducer() from React-Toolkit (RTK).
 * This version adds support for redux-loops by passing a `cmd` as an optional third parameter in the reducer call.
 * That `cmd` is a proxy for redux-loop's "Cmd" and can be use in the same way.
 *
 * Unlike RTK's createReducer, this version does allow you to add multiple reducer cases for the same dispatch. Be
 * careful not to make assumptions about which reducer will run first! This is best used when there are no dependencies.
 *
 * The following RTK functionality has been removed: addMatcher(), addDefaultCase(), "Map Object" notation
 *
 * Direct state mutation via return values is still supported but a special builder function `addNoImmerCase`
 * is better suited for those situations because it enforces read only state. This case will also not send a redux-loop
 * cmd as a third parameter because you can use redux-loops the normal way.
 *
 * Example: Using redux-loop
 * ```
 * builder.addCase(myAction, (state, action: PayloadAction<ClientAdded>, cmd) => {
 * 		state.blah = action.payload.blah; // Do normal reducer stuff
 *
 * 		// Create a loop, see redux-loop documentation
 * 		cmd.run(getLinkerState, {
 * 			args : [windowName],
 * 			successActionCreator : actions.initializeWindow
 * 		})
 * })
 * ```
 *
 * Use `Cmd.getState`, `Cmd.dispatch` or `Cmd.none` by importing them from redux-loop. There aren't equivalents for cmd because
 * redux-loop uses the "unique symbol" type which cannot be copied (or so it seems).
 *
 * Example: Using Cmd.getState
 * ```
 * cmd.run(getLinkerState, { args: [Cmd.getState] })
 * ```
 *
 * Example: using addNoImmerCase
 * ```
 * builder.addNoImmerCase(myAction, (state, action: PayloadAction<ClientAdded>) => {
 * 		const newState = produce(state, (draft) => {
 * 			draft.blah=action.payload.blah; // Good!
 * 			state.blah=action.payload.blah; // Typescript error, you can't modify state!
 * 		});
 *
 * 		// Use redux-loop the old fashioned way
 * 		return loop(
 * 			newState,
 * 			Cmd.action(actions.dummy("blah"))
 * 		)
 * });
 *
 * ```
 *
 * Internals:
 *
 * Like RTK, the reducer cases are reduced to single nextState and returned to redux. To extract the loops
 * we use the CmdProxy to temporarily store the loop commands. They are compiled into a single `Cmd.list`
 * at the very end of the dispatch cycle. So in effect, redux is always receiving a loop from this reducer
 * rather than a state. This will therefore not work correctly if redux-loops middleware is not installed!
 */
export declare function createReducer<S>(initialState: S, mapOrBuilderCallback: (builder: ActionReducerMapBuilder<S>) => void, hook?: CreateReducerHook): Reducer<S>;
/**
 * Use this instead of console.log() when inside of reducers. Since addCase uses
 * immer under the covers, console.log will print out the entire immer proxy object which is ugly
 */
export declare const log: (label: any, value: any) => void;
/**
 * Predicate function for comparing an actionCreator to a raw action
 * Example: `addMatcherCase(is(action.joinChannels), ...`
 */
export declare const is: (actionCreator: any) => (action: AnyAction) => boolean;
export {};
//# sourceMappingURL=createReducer.d.ts.map