import { FlowfulError } from './error'; export const ACTION_MODE_SINGLE = 'single'; export type ActionModeSingle = typeof ACTION_MODE_SINGLE; export const ACTION_MODE_MULTI = 'multi'; export type ActionModeMulti = typeof ACTION_MODE_MULTI; export type ActionMode = ActionModeSingle | ActionModeMulti; export interface IAction { readonly type: string; readonly mode: Mode; readonly creator: IActionCreator; readonly payload: Payload; } export type Payload = T extends IActionCreator ? P : never; export interface IActionCreator< Payload = any, Mode extends ActionMode = ActionMode, Arguments extends any[] = any[], A extends IAction = IAction > { (...args: Arguments): A; readonly type: string; readonly mode: Mode; } export function actionCreatorSingle(type: string): IActionCreator { function ActionCreator(payload: Payload) { return { type, mode: ACTION_MODE_SINGLE as ActionModeSingle, payload, creator: ActionCreator, }; } ActionCreator.type = type; ActionCreator.mode = ACTION_MODE_SINGLE as ActionModeSingle; return ActionCreator; } export function actionCreatorMulti(type: string): IActionCreator { function ActionCreator(payload: Payload) { return { type, mode: ACTION_MODE_MULTI as ActionModeMulti, payload, creator: ActionCreator, }; } ActionCreator.type = type; ActionCreator.mode = ACTION_MODE_MULTI as ActionModeMulti; return ActionCreator; } export function actionCreator( type: string, mode?: ActionModeSingle ): IActionCreator; export function actionCreator( type: string, mode: ActionModeMulti ): IActionCreator; export function actionCreator( type: string, mode: ActionMode = ACTION_MODE_SINGLE ): IActionCreator { if (mode === ACTION_MODE_SINGLE) { return actionCreatorSingle(type); } else if (mode === ACTION_MODE_MULTI) { return actionCreatorMulti(type); } else { throw new FlowfulError( `[Flowful][actionCreator] Invalid mode: "${mode}" for action "${type}". Must be "${ACTION_MODE_SINGLE}" or "${ACTION_MODE_MULTI}".`, { type, mode } ); } } export function actionCreatorDefault( type: string, defaultPayload: Payload, mode?: ActionModeSingle ): IActionCreator; export function actionCreatorDefault( type: string, defaultPayload: Payload, mode: ActionModeMulti ): IActionCreator; export function actionCreatorDefault( type: string, defaultPayload: Payload, mode?: Mode ): IActionCreator { if (mode === undefined) { mode = ACTION_MODE_SINGLE as Mode; } if (mode !== ACTION_MODE_SINGLE && mode !== ACTION_MODE_MULTI) { throw new FlowfulError( `[Flowful][actionCreatorDefault] Invalid action mode: "${mode}" for action "${type}". Must be "${ACTION_MODE_SINGLE}" or "${ACTION_MODE_MULTI}".`, { type, mode } ); } function ActionCreatorDefault(payload?: Payload) { return { type, mode, payload: payload !== undefined ? payload : defaultPayload, creator: ActionCreatorDefault, }; } ActionCreatorDefault.type = type; ActionCreatorDefault.mode = mode; return ActionCreatorDefault as IActionCreator; }