Created
March 3, 2019 05:33
-
-
Save jakobz/ae3e5567e20fff3d66d9e8852a9a655a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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