Remeda Pipe()
Functional programming in Typescript
Since ES5, Javascript has included some functional programming methods on the Array prototype of .map
, .filter
, .sort
, and .reduce
. These can be chained like:
1array.filter().map().sort()
Imagine if you had to call each of these functions separately and pass the output of one to another – it would get messy!
Can we achieve this same pattern in our own custom functions?
The problem
Often to help with readability, I will wrap common code into a named function. This keeps it semantically grouped, and allows code folding in VScode (without the #region syntax).
However, these functions then need to be invoked, and can become messy like:
1const doWork = async (input: string): number => input.length2const result = await doWork('work')3const processResult = (result: Awaited<ReturnType<typeof doWork>>) => {...}4processResult(result)5const cleanup = async () => {...}6cleanup()
It works, but it can become hard to quickly see the flow of functions. Function invocations mixed with function declarations. Especially if some unrelated code is added between.
This is a perfect case for functional programming pipes!
Introdcing R.pipe()
It looks like this:
1import r * as R from 'remeda' // tree shaking supported! 2 3// define the functions 4const doWork = async (input: string): number => {...} 5const processResult = (result: Awaited<ReturnType<typeof doWork>>) => {...} 6const cleanup = async () => {...} 7 8// call them sequentially in a pipe! 9r.pipe( 10 await doWork('input'), // the result of this is passed to the next pipe item!11 async (x) => processResult(x), // this pipe item receives the result as a callback, and passes it to it's funciton12 async () => cleanup() // async and await supported inside the pipe!13)
This is a simple contrived example, but in real-world cases, it can dramatically improve the readability of long unwiedly programs.
In this way, you can chain together your own functions.