I love small bits that do great things. This time it's about adding the pipe()
method to any object, e.g.
const items = [ { price: 1 }, { price: 2 } ]
const sumPrice = (acc, item) => acc + item.price
const sum = pipeable(items)
.pipe(items => items.reduce(sumPrice, 0))
.pipe(sum => sum++)
And on and on, you can pipe the result of one callback to another, with the first callback receiving the pipeable value.
Now, how do we type this so that it makes sense in TypeScript?
export type Pipeable<I> = {
pipe<O>(transform: (input: I) => O): O & Pipeable<O>
}
Having the type definition of the Pipeable
type let's try to implement it:
function pipeable<I>(input: I) {
const result = clone(input)
if ((result as any).pipe) {
throw new Error('Error: object is already pipeable')
}
const pipeableResult = result as Pipeable<I>
pipeableResult.pipe = <O>(transform: (input: I) => O) => pipeable<O>(transform(result))
return result as I & Pipeable<I>
}
Depending on your needs, clone
can either have a trivial implementation like this one:
function clone<T>(input: T): T {
return JSON.parse(JSON.stringify(input))
}
or, you could go full on with packages such as clone-deep.
Top comments (0)