import { Action } from 'redux'; const allActionCreators: string[] = []; export interface ActionOf extends Action { readonly type: string; readonly payload: Payload; } export interface ActionCreator { readonly type: string; (payload: Payload): ActionOf; } export interface NoPayloadActionCreator { readonly type: string; (): ActionOf; } export interface ActionCreatorFactory { create: () => ActionCreator; } export interface NoPayloadActionCreatorFactory { create: () => NoPayloadActionCreator; } export const actionCreatorFactory = (type: string): ActionCreatorFactory => { const create = (): ActionCreator => { return Object.assign((payload: Payload): ActionOf => ({ type, payload }), { type }); }; if (allActionCreators.some(t => (t && type ? t.toLocaleUpperCase() === type.toLocaleUpperCase() : false))) { throw new Error(`There is already an actionCreator defined with the type ${type}`); } allActionCreators.push(type); return { create }; }; export const noPayloadActionCreatorFactory = (type: string): NoPayloadActionCreatorFactory => { const create = (): NoPayloadActionCreator => { return Object.assign((): ActionOf => ({ type, payload: undefined }), { type }); }; if (allActionCreators.some(t => (t && type ? t.toLocaleUpperCase() === type.toLocaleUpperCase() : false))) { throw new Error(`There is already an actionCreator defined with the type ${type}`); } allActionCreators.push(type); return { create }; }; export interface NoPayloadActionCreatorMock extends NoPayloadActionCreator { calls: number; } export const getNoPayloadActionCreatorMock = (creator: NoPayloadActionCreator): NoPayloadActionCreatorMock => { const mock: NoPayloadActionCreatorMock = Object.assign( (): ActionOf => { mock.calls++; return { type: creator.type, payload: undefined }; }, { type: creator.type, calls: 0 } ); return mock; }; export const mockActionCreator = (creator: ActionCreator) => { return Object.assign(jest.fn(), creator); }; // Should only be used by tests export const resetAllActionCreatorTypes = () => (allActionCreators.length = 0);