type Transform> = (x: T) => U; type TransformChain> = { (x: T): U; use(transform: Transform): (() => void); }; export const createTransformChain = (...transforms: Transform[]): TransformChain => { let chain = transforms; const call = (x: T): T => chain.reduce((x, transform) => transform(x), x); const use = (transform: Transform): (() => void) => { chain.push(transform); return (): void => { chain = chain.filter((t) => t !== transform); }; }; return Object.assign(call, { use }); }; export const createAsyncTransformChain = (...transforms: Transform>[]): TransformChain> => { let chain = transforms; const call = (x: T): Promise => chain.reduce((x, transform) => x.then(transform), Promise.resolve(x)); const use = (transform: Transform>): (() => void) => { chain.push(transform); return (): void => { chain = chain.filter((t) => t !== transform); }; }; return Object.assign(call, { use }); };