provided solution for my action creators
// Basic actions
// Removed payload and error for this demonstration
interface FluxStandardAction<T extends string, Meta = undefined> {
type: T;
meta?: Meta;
}
enum ActionType {
One = "one",
Two = "two",
}
const action1 = () => ({ type: ActionType.One });
const action2 = () => ({ type: ActionType.Two });
type Action =
| ReturnType<typeof action1>
| ReturnType<typeof action2>
;
// Higher order action modifiers that augment the action's meta properties
interface WithGreekLetter {
meta: {
greek: string;
}
}
const withGreekLetter = <T extends string, M extends {}, A extends FluxStandardAction<T, M>>(action: () => A, greek: string) =>
(): A & WithGreekLetter => {
let act = action();
let meta = Object.assign({}, act.meta, { greek });
return Object.assign(act, { meta });
}
const isWithGreekLetter = (a: any): a is WithGreekLetter =>
a['meta'] && a['meta']['greek'];
// A basic reusable reducer
type State = number;
const initialState: State = 0;
function plainReducer(state: State, action: Action): State {
switch (action.type) {
case ActionType.One:
return state + 1;
case ActionType.Two:
return state + 2;
default:
return state;
}
}
// The higher-order reducer
const forGreekLetter = <S, A>(reducer: (state: S, action: A) => S, greek: string) =>
(state: S, action: A) =>
isWithGreekLetter(action) && action.meta.greek === greek ? reducer(state, action) : state;
// Build the concrete action creator and reducer instances
const ALPHA = 'alpha';
const BETA = 'beta';
let oneA = withGreekLetter(action1, ALPHA);
let oneB = withGreekLetter(action1, BETA);
let twoA = withGreekLetter(action2, ALPHA);
let twoB = withGreekLetter(action2, BETA);
let reducerAlphaNoInitial = forGreekLetter(plainReducer, ALPHA);
let reducerA = (state = initialState, action: Action) => reducerAlphaNoInitial(state, action);
let reducerBetaNoInitial = forGreekLetter(plainReducer, BETA);
let reducerB = (state = initialState, action: Action) => reducerBetaNoInitial(state, action);
// Exercise the action creators and reducers
let actions = [oneB(), oneA(), twoB(), twoA(), twoB()];
let stateA: State | undefined = undefined;
let stateB: State | undefined = undefined;
for (const action of actions) {
stateA = reducerA(stateA, action);
stateB = reducerB(stateB, action);
}
console.log({ stateA, stateB });
// {stateA: 3, stateB: 5}
FluxStandardAction
const isAction = (a: any): a is Action =>
Object.values(ActionType).includes(a['type']);
export const onlySpecificAction = <S, A1, A2>(reducer: (s: S, a: A1) => S, isA: IsA<A1>) =>
(state: S, action: A2) =>
isA(action) ? reducer(state, action) : state;