import type { Draft } from 'immer';
import type { AnyAction, PayloadAction } from './types';
import type { MapSelectorsTo, ReMappedSelectors } from './slice-utils';
/** Type alias for case reducers when `slice` is blank or undefined */
declare type CaseReducer<S = any, P = any> = (state: Draft<S>, payload: P) => S | void | undefined;
/** Type alias for the generated reducer */
export declare type Reducer<S = any, A extends AnyAction = AnyAction> = (state: S | undefined, action: A) => S;
/**
 * A map of case reducers for creating a standard reducer
 * @export
 * @template SS is the `SliceState`
 * @template Ax  is the `ActionsMap`
 */
export declare type CasesBase<SS> = {
    [s: string]: CaseReducer<SS>;
};
export declare type CasesBuilder<SS, Ax extends {}> = {
    [K in keyof Ax]: CaseReducer<SS, Ax[K]>;
};
/** Generic Action Map interface */
export interface ActionMap<P = any> {
    [Action: string]: P;
}
export interface AnyState {
    [slice: string]: any;
}
/** Type alias for generated selectors */
export declare type Selectors<SS> = {
    selectSlice: (state: SS) => SS;
} & (SS extends any[] | ReadonlyArray<any> ? {} : SS extends AnyState ? {
    [key in keyof SS]: (state: SS) => SS[key];
} : {});
declare type InferTypeLiteral<TyO extends string, Fallback> = TyO extends string ? TyO : Fallback extends string ? Fallback : never;
declare type InferTypeLiteralWithSliceName<SliceName extends string | '', TyO extends string, Fallback> = SliceName extends '' ? InferTypeLiteral<TyO, Fallback> : `${SliceName}/${InferTypeLiteral<TyO, Fallback>}`;
/** Type alias for generated action creators */
export declare type ActionCreatorsMap<A, TyO extends {
    [K in keyof A]?: string;
} = {}, SliceName extends string = ''> = {
    [key in keyof A]: ActionCreator<A[key], InferTypeLiteralWithSliceName<SliceName, NonNullable<TyO[key]>, key>> & {
        type: InferTypeLiteralWithSliceName<SliceName, NonNullable<TyO[key]>, key>;
        toString: () => InferTypeLiteralWithSliceName<SliceName, NonNullable<TyO[key]>, key>;
    };
};
declare type ActionCreator<A, T extends string> = 0 extends A & 1 ? (payload?: any) => PayloadAction<any, T> : unknown extends A ? () => PayloadAction<undefined, T> : [undefined] extends [A] ? (payload?: A) => PayloadAction<A, T> : [null] extends [A] ? (payload: A) => PayloadAction<A, T> : keyof A extends never ? () => PayloadAction<undefined, T> : (payload: A) => PayloadAction<A, T>;
declare type PayloadTypeMap<Cases extends CasesBase<any>> = {
    [K in keyof Cases]: Cases[K] extends (s: any, p: infer P) => any ? P : never;
};
export declare type ActionCreatorsMapFromCases<Cases extends CasesBase<any>, TyO = {}, SliceName extends string = ''> = ActionCreatorsMap<PayloadTypeMap<Cases>, TyO, SliceName>;
/** Map of computed selectors */
declare type ComputedMap<S> = {
    [s: string]: (state: S) => any;
};
/** Hack used to make values of `typeOverrides` Object string literals */
declare type Const<TyO> = {
    [K in keyof TyO]: TyO[K];
};
/**
 * @interface Slice
 * @description The interface of the object returned by createSlice
 * @template Ax - is the [Action] creator interface
 * @template SS - [SliceState]
 * @template S - [State]
 * @template Slc - [slice]
 */
export interface Slice<SliceName extends string, Cases extends CasesBase<SS>, SS, SelectorMap extends {
    [s: string]: (state: SS) => any;
}, Computed extends {
    [s: string]: (state: SS) => any;
}, TyO extends {
    [K in keyof Cases]?: string;
}> {
    /**
     * The name of the slice
     *
     * @type {SliceName}
     * @memberof Slice
     */
    name: SliceName;
    /**
     * @description The generated reducer
     *
     * @type {Reducer<SS, AnyAction>}
     * @memberof Slice
     */
    reducer: Reducer<SS, AnyAction>;
    /**
     * An object containing the automatically generated action creators
     * @type { [s:string]: (payload:any)=> PayloadAction }
     * @memberof Slice
     */
    actions: ActionCreatorsMapFromCases<Cases, TyO, SliceName>;
    /**
     * Helper utility for mapping selectors to paths
     *
     * @example
     * // if your reducer is for a todos slice i.e
     *
     * const todosSlice = createSlice({
     *   //...
     * })
     *
     * const rootReducer = combineReducers({
     *    todos: todosSlice.reducer
     * });
     * const store = createStore(rootReducer);
     *
     * const todosSelector = todosSlice.mapSelectorsTo('todos');
     *
     * const mapStateToProps = (state: typeof store.getState) => todosSelector.selectSlice(state)
     *
     * @memberof Slice
     */
    reMapSelectorsTo: MapSelectorsTo<SelectorMap & Computed>;
    selectors: ReMappedSelectors<[SliceName], SelectorMap & Computed>;
}
/**
 * Options for `createSlice` utility
 *
 * @interface CreateSliceOptions
 * @template SS The `SliceState` type
 * @template Ax The Actions map, format - `{ [caseName]: typeof payload }`
 * @template Cx The computed selectors map, format - `{ [selectorName]: returnType }`
 * @template TyO The type overrides map, format - `{[caseName]: <string>typeOverride}`
 */
interface CreateSliceOptions<SliceName extends string, SS, Cases extends CasesBase<SS>, Cx extends ComputedMap<SS>, TyO> {
    /**
     *The slice name
     *
     * @type {SliceName}
     * @memberof CreateSliceOptions
     */
    name: SliceName;
    /**
     * The initial State, same as standard reducer
     *
     * @type {SS}
     * @memberof CreateSliceOptions
     */
    initialState: SS;
    /**
     * @description - An object whose methods represent the cases the generated reducer handles,
     * can be thought of as the equivalent of [switch-case] statements in a standard reducer.
     *
     * @type {Cases}
     * @example
     * interface Todo {title: string, completed: boolean};
     * const todoSlice = createSlice({
     *   initialState: [] as Todo[],
     *   cases: {
     *     addTodo: (state, payload: string) => {
     *       state.push({title: payload, completed: false})
     *     }
     *   }
     * })
     * @memberof CreateSliceOptions
     */
    cases: Cases;
    /**
     * @description computed selectors for this slice, will be memoized using the `memoize-state` lib
     * https://github.com/theKashey/memoize-state
     *
     * @see note: (js-users ignore) if using `this` to access other selectors,
     * ReturnType should be explicit to prevent `typescript` errors,
     * see https://github.com/dudeonyx/redux-ts-starter-kit/issues
     * @example
     * type Todo = {title: string, completed: boolean};
     * const todosSlice = createSlice({
     *   initialState: [] as Todo[],
     *   computed: {
     *     getCompletedTodos: state => state.filter(todo => todo.completed),
     *     getCompletedTodosLength(state): number {
     *       return this.getCompletedTodos(state).length;
     *     },
     *   }
     *   cases: {
     *     //...
     *   }
     * })
     * @type {ComputedMap<SS, Cx>}
     * @memberof CreateSliceOptions
     */
    computed: Cx;
    /**
     * @description Type overrides to override the `type` which case reducers respond to
     * which by default is simply the name of the case reducer.
     * i.e the `addTodo` case reducer in `cases: { addTodo: (state, payload) => {//...}, }`
     * would by default respond to actions of type `addTodo` e.g. `{ type: 'addTodo', payload: 'Jog' }`.
     * This can be changed thanks to the `typeOverrides` option.
     * For example the changed the type to `ADD_TODO` instead see the example below.
     *
     * It should be noted that the action creators `createSlice` generates automatically account for typeOverrides
     *
     * @example
     * const todoSlice = createSlice({
     *     cases: {
     *         addTodo: (state, payload: string) => {
     *             state.push({title: payload, completed: false})
     *         },
     *         deleteTodo: //...,
     *         setCompleted: //...,
     *     },
     *     typeOverrides: {
     *         addTodo: 'ADD_TODO'
     *     }
     * })
     *
     * @type {TyO}
     * @memberof CreateSliceOptions
     */
    typeOverrides?: TyO;
}
/**
 * @description Generates a redux state tree slice, complete with a `reducer`,
 *  `action creators`, `mapSelectorsTo` and `createNameSpace`
 *
 * @export
 * @template Actions - A map of action creator names and payloads, in the form `{[caseName]: typeof payload}`,
 *  a payload type of `never` | `undefined` | `void` can be used to indicate that no payload is expected
 * @template SliceState - The interface of the initial state,
 * @template Computed
 * @template TypeOverrides
 * @param {CreateSliceOptions<SliceState, Actions, Computed, TypeOverrides>} options
 * @returns {(Slice<
 *   SliceName,
 *   Cases,
 *   SliceState,
 *   Selectors<SliceState>,
 *   AreStrictlyEqual<
 *     Computed,
 *     { [s: string]: (state: SliceState) => any } | {},
 *     {},
 *     Computed
 *   >,
 *   TyO
 * >)}
 * @type   RemoveIndex<Computed> is needed to prevent `Computed` infering as { [s: string]: (state: SliceState) => any } when computed
 *         is undefined in the argument to `createSlice`. This would otherwise break type safety.
 */
export declare function createSlice<SliceName extends string, Cases extends CasesBase<SliceState>, SliceState, Computed extends ComputedMap<SliceState>, TyO extends {
    [K in keyof Cases]?: string;
} = {}>({ cases, name, initialState, computed, typeOverrides, }: CreateSliceOptions<SliceName, SliceState, Cases, Computed, Const<TyO>>): Slice<SliceName, Cases, SliceState, Selectors<SliceState>, Computed, TyO>;
export declare function createSlice<SliceName extends string, Cases extends CasesBase<SliceState>, SliceState, Computed extends Record<string, never> = Record<string, never>, TyO extends {
    [K in keyof Cases]?: string;
} = {}>({ cases, name, initialState, typeOverrides, }: Omit<CreateSliceOptions<SliceName, SliceState, Cases, {}, Const<TyO>>, 'computed'>): Slice<SliceName, Cases, SliceState, Selectors<SliceState>, {}, TyO>;
export {};
