type Work = (...args: any[]) => T; type Enhancer = (next: Work) => Work; type Middleware = (setup: Setup) => Enhancer; export default function concatMiddleware( ...middleware: Middleware[] ): Middleware { return setupArgs => { const setup = middleware.reduce( (setup, middleware) => (middleware ? [...setup, middleware(setupArgs)] : setup), [] ); return last => { const stack = setup.slice(); const work = (index: number) => (...runArgs) => { const next = stack[+index]; return (next ? next(work(index + 1)) : last)(...runArgs); }; return work(0); }; }; }