Skip to content

Instantly share code, notes, and snippets.

@micimize
Created December 30, 2017 19:24
Show Gist options
  • Save micimize/63498fdcd3301787460128ecbeaefe15 to your computer and use it in GitHub Desktop.
Save micimize/63498fdcd3301787460128ecbeaefe15 to your computer and use it in GitHub Desktop.
redux routines with tuple actions and switch reducers
import { curry, __, mapObjIndexed, chain, pick, pipe } from 'ramda'
import { bindActionCreators, Dispatch, ActionCreatorsMapObject } from 'redux'
import { Creator, Switch } from './actions'
enum RoutineAction {
Trigger = 'TRIGGER',
Request = 'REQUEST',
Success = 'SUCCESS',
Failure = 'FAILURE',
}
type RoutineActions<Prefix extends string> = {
TRIGGER: [ Prefix, RoutineAction.Trigger ],
REQUEST: [ Prefix, RoutineAction.Request ],
SUCCESS: [ Prefix, RoutineAction.Success ],
FAILURE: [ Prefix, RoutineAction.Failure ],
}
type ActionTuple<Prefix extends string> =
| [ Prefix, RoutineAction.Trigger ]
| [ Prefix, RoutineAction.Request ]
| [ Prefix, RoutineAction.Success ]
| [ Prefix, RoutineAction.Failure ]
type BasePayload = any
type BasePayloads = Partial<{
trigger: BasePayload,
request: BasePayload,
success: BasePayload
failure: BasePayload
}>
// TODO maybe there's a type level way to dry this up,
// unfinished because switch is complicated
/* or there will be in the future
type Routine<Prefix extends string, Payloads extends BasePayloads> = {
actions: RoutineActions<Prefix>,
switch: Switch.Dict(actions),
trigger: Creator<[ Prefix, RoutineAction.Trigger ], Payloads['trigger']>,
request: Creator.Empty<[ Prefix, RoutineAction.Request ]>,
success: Creator<[ Prefix, RoutineAction.Success ], Payloads['success']>,
failure: Creator<[ Prefix, RoutineAction.Failure ], Payloads['failure']>,
}
*/
function routineActions<Prefix extends string>(prefix: Prefix): RoutineActions<Prefix> {
return {
TRIGGER: [ prefix, RoutineAction.Trigger ],
REQUEST: [ prefix, RoutineAction.Request ],
SUCCESS: [ prefix, RoutineAction.Success ],
FAILURE: [ prefix, RoutineAction.Failure ],
}
}
function routineCreators<
Prefix extends string,
Payloads extends BasePayloads
>(actions: RoutineActions<Prefix>){
return {
trigger: Creator<typeof actions.TRIGGER, Payloads['trigger']>(actions.TRIGGER),
request: Creator.Empty<typeof actions.REQUEST>(actions.REQUEST),
success: Creator<typeof actions.SUCCESS, Payloads['success']>(actions.SUCCESS),
failure: Creator<typeof actions.FAILURE, Payloads['failure']>(actions.FAILURE),
}
}
function bindRoutineActions(
routines: { [routine: string]: ActionCreatorsMapObject & any },
dispatch: Dispatch<any>
){
return mapObjIndexed(
pipe(
pick(['trigger', 'request', 'success', 'failure']),
curry(bindActionCreators)(__, dispatch)
),
routines
)
}
function extractRoutineActions(
routines: { [routine: string]: ActionCreatorsMapObject & any },
) {
return mapObjIndexed(
pick(['trigger', 'request', 'success', 'failure']),
routines
)
}
function createRoutine<
Prefix extends string,
Payloads extends BasePayloads
>(prefix: Prefix){
let actions = routineActions(prefix)
let _Actions: ActionTuple<Prefix> = actions.TRIGGER // for extracting the Action type
let creators = routineCreators<Prefix, Payloads>(actions)
return {
actions,
_Actions,
switch: Switch.Dict(actions),
...creators
}
}
let fetchRoutine = createRoutine<'FETCH', {}>('FETCH')
fetchRoutine.switch<{ state?: 'LOADING' | 'SUCCESS' | 'FAILURE', data?: any }>({
TRIGGER: {},
REQUEST: { state: 'LOADING' },
SUCCESS: { state: 'SUCCESS', data: 'whatever' },
FAILURE: { state: 'FAILURE', data: 'oh no' },
DEFAULT: {}
})
export default createRoutine
export {
RoutineAction,
RoutineActions,
BasePayloads,
routineActions,
routineCreators,
bindRoutineActions,
extractRoutineActions
}
@micimize
Copy link
Author

related to switch-experiments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment