export type Action = { type: T; meta?: Record; payload?: TPayload; }; export type ActionGenerator< TType extends string = string, TPayloadGen = (...args: any[]) => any, > = { type: TType; } & (TPayloadGen extends (...args: any) => any ? ReturnType extends void ? (...args: Parameters) => { type: TType; } : (...args: Parameters) => { type: TType; payload: ReturnType; } : (...args: any[]) => { type: TType; payload?: unknown }); export function action< TType extends string, TPayload extends (...args: any) => any, >( type: TType, payloadFunction?: TPayload, transformer?: Function, ): ActionGenerator { let generator: any = function (...payloadArg:any[]) { const result: Action = { type }; if (payloadFunction) { result.payload = payloadFunction(...payloadArg); } else { if (payloadArg[0] !== undefined) result.payload = payloadArg[0]; } return result; }; if (transformer) { const orig = generator; generator = (...args: any) => transformer(orig(...args), args); } generator.type = type; return generator; }