Last active
June 21, 2021 04:10
-
-
Save freddi301/5c01af6c935d4dc4e71acceb3eea166a to your computer and use it in GitHub Desktop.
TypeScript Redux reduce boilerplate
This file contains hidden or 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
export interface ActionHandler<State, Payload> { | |
(state: State, payload: Payload): State; | |
} | |
export interface ActionHandlers<State> { | |
[index: string]: ActionHandler<State, any>; | |
} | |
export interface Action<Type, Payload> { | |
type: Type; | |
payload: Payload; | |
} | |
export interface ActionCreator<Type, Payload> { | |
(payload: Payload): Action<Type, Payload>; | |
} | |
export interface ActionCreators { | |
[index: string]: ActionCreator<any, any>; | |
} | |
type ActionCreatorsFrom<Handlers extends ActionHandlers<any>> = { | |
[Type in keyof Handlers]: ActionCreator< | |
Type, | |
ExtractPayoladType<Handlers[Type]> | |
> | |
}; | |
type ExtractPayoladType< | |
T extends ActionHandler<any, any> | |
> = T extends ActionHandler<any, infer Payload> ? Payload : any; | |
export function actionsOf<State, Handlers extends ActionHandlers<State>>( | |
handlers: Handlers | |
): ActionCreatorsFrom<Handlers> { | |
const actionsCreators: ActionCreatorsFrom< | |
Handlers | |
> = {} as ActionCreatorsFrom<Handlers>; | |
Object.keys(handlers).forEach(type => { | |
actionsCreators[type] = (payload: any) => ({ type, payload }); | |
}); | |
return actionsCreators; | |
} | |
export function reducerOf<State, Handlers extends ActionHandlers<State>>( | |
handlers: Handlers | |
) { | |
return < | |
Name extends keyof Handlers, | |
Payload extends ExtractPayoladType<Handlers[Name]> | |
>( | |
state: State, | |
action: Action<Name, Payload> | |
): State => { | |
if (!handlers[action.type]) { | |
throw new Error(`Unhandled action type: ${action.type}`); | |
} | |
return handlers[action.type](state, action.payload); | |
}; | |
} | |
export type DispatchOf<State, Handlers extends ActionHandlers<State>> = < | |
Name extends keyof Handlers, | |
Payload extends ExtractPayoladType<Handlers[Name]> | |
>( | |
action: Action<Name, Payload> | |
) => Action<Name, Payload>; | |
export function createStateManagment<State>() { | |
return <Handlers extends ActionHandlers<State>>(handlers: Handlers) => { | |
return { | |
actions: actionsOf(handlers), | |
reducer: reducerOf(handlers), | |
dispatch: (null as any) as DispatchOf<State, Handlers>, | |
}; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment