Skip to content

Instantly share code, notes, and snippets.

@typoerr
Last active July 14, 2017 14:20
Show Gist options
  • Select an option

  • Save typoerr/bcbb2c8a81b100abf074844c69672a0e to your computer and use it in GitHub Desktop.

Select an option

Save typoerr/bcbb2c8a81b100abf074844c69672a0e to your computer and use it in GitHub Desktop.
export interface Action<T = any, K extends keyof T = any> {
type: K;
payload: T[K];
}
export type MapAction<T = any> = {
[K in keyof T]: Action<T, K>
};
export type MapActionHandler<S, A extends MapAction> = {
[K in keyof A]: (state: S, payload: A[K]['payload']) => S
};
export type ActionHandler<S, A> = MapActionHandler<S, MapAction<A>>;
export default function createReducer<S>(initialState: S, handler: ActionHandler<any, any>) {
return function reducer(state: S = initialState, action: any): S {
return handler[action.type] ? handler[action.type](state, action.payload) : state;
};
}
@typoerr

typoerr commented Jul 14, 2017

Copy link
Copy Markdown
Author
import createReducer, { ActionHandler } from './../create-reducer';

interface S {
    count: number;
}

interface A {
    a: string;
    b: number;
}

test('createReducer', () => {
    const state: S = { count: 0 };
    const handler: ActionHandler<S, A> = {
        a: (s, p) => ({ count: s.count + p.length }),
        b: (s, p) => ({ count: s.count + p })
    };

    const reducer = createReducer(state, handler);

    const s1 = reducer(state, { type: 'a', payload: 'str' });
    const s2 = reducer(state, { type: 'b', payload: 1 });
    const s3 = reducer(state, { type: 'c', payload: 1 });

    expect(s1).toEqual({ count: 3 });
    expect(s2).toEqual({ count: 1 });
    expect(s3).toEqual({ count: 0 });
    expect(state).toEqual({ count: 0 });
});

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