Skip to content

Instantly share code, notes, and snippets.

@jakobz
Created March 3, 2019 05:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakobz/ae3e5567e20fff3d66d9e8852a9a655a to your computer and use it in GitHub Desktop.
Save jakobz/ae3e5567e20fff3d66d9e8852a9a655a to your computer and use it in GitHub Desktop.
import { Reducer } from "redux";
import { Dispatch } from "react-redux";
export type ReducerCur<TState, TPayload = any> = (payloyoad: TPayload) => (state: TState) => TState;
export type ActionCreator<TPayload> = (payload: TPayload) => ({ type: string } & TPayload);
type GetActionCreator<TState, T> = T extends ReducerCur<TState, infer TPayload> ? ActionCreator<TPayload> : void;
export type ActionCreatorsSet<TState, T> = { [TName in keyof T]: GetActionCreator<TState, T[TName]> };
export interface Bundle<TState, TReducersSet> {
reducer: Reducer<TState, any>;
actionCreators: ActionCreatorsSet<TState, TReducersSet>;
bind(dispatch: Dispatch<TState>): ActionCreatorsSet<TState, TReducersSet>;
}
export interface BuildReducerOptions {
prefix?: string;
}
export function buildReducer<TState, TReducersSet>(
initialState: TState,
reducersSet: TReducersSet,
options?: BuildReducerOptions
): Bundle<TState, TReducersSet> {
const effectiveOptions: BuildReducerOptions = options || {};
const reducers: Record<string, ReducerCur<TState>> = {};
const actionCreators: any = {};
const actionDispatchers: any = {};
Object.keys(reducersSet).forEach((name: string) => {
let type = name.replace(/(?:^|\.?)([A-Z])/g, (x, y) => { return "_" + y.toLowerCase(); }).replace(/^_/, "").toUpperCase();
if (effectiveOptions.prefix) {
type = effectiveOptions.prefix + '_' + type;
}
reducers[type] = (reducersSet as any)[name];
actionCreators[name] = (payload: any) => ({ type, ...payload });
actionDispatchers[name] = (dispatch: Dispatch<TState>) => (payload: any) => dispatch({ ...payload, type });
});
function reducer(state: any, action: any) {
if (typeof state === 'undefined') {
return initialState;
}
const reducerCar: ReducerCur<any, any> = (reducers as any)[action.type];
const newState = reducerCar ? reducerCar(action)(state) : state;
return newState;
}
function bind(dispatch: Dispatch<TState>) {
const actionEmitters: any = {};
Object.keys(actionDispatchers).forEach(key => actionEmitters[key] = actionDispatchers[key](dispatch));
return actionEmitters;
}
return { reducer, actionCreators, bind };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment