DEV Community

Michael Z
Michael Z

Posted on • Updated on • Originally published at michaelzanggl.com

Turn any non fluent API into a fluent one - tap tap tap

Originally posted at michaelzanggl.com. Subscribe to my newsletter to never miss out on new content.

Inspired by Laravel's tap helper, I recently created a small little library for tapping in JavaScript. It's yet another interesting thing we can do thanks to ES6 proxies.

GitHub logo MZanggl / taptaptap

Turn non fluent apis into fluent ones

Turns non fluent APIs into fluent APIs

npm install taptaptap

Examples

Take Array.prototype.push for example. It returns the new length of the array, making chaining impossible.

const numbers = []
numbers.push(1)
numbers.push(2)
Enter fullscreen mode Exit fullscreen mode

Wrapping the array inside "tap" allows us to chain everything together nicely.

const { tap } = require('taptaptap')
const numbers = tap([])
    .push(1)
    .push(2)
Enter fullscreen mode Exit fullscreen mode

tap uses ES6 proxies to make sure each function gets executed, but returns the initially passed value (in this case, the numbers array).


One more example using classes

class User {
    name = null
    setName(name) {
        this.name = name
    }
    getId() {
        return this.id
    }
    save() {
        // persist data
        this.id = this.createUUID
Enter fullscreen mode Exit fullscreen mode

Take Array.prototype.push for example. It returns the new length of the array, making chaining impossible.

const numbers = []
numbers.push(1)
numbers.push(2)
Enter fullscreen mode Exit fullscreen mode

Wrapping the array inside "tap" allows us to chain everything together nicely.

const { tap } = require('taptaptap')

const numbers = tap([])
    .push(1)
    .push(2)
Enter fullscreen mode Exit fullscreen mode

Each function that gets executed simply returns the originally passed value again.


There is also another use case for tap which allows grouping common logic.

Imagine you have a test like this

const user = await User.query().latest().first()

expect(user.name).toBe('test name')
expect(user.bio).toBe('test bio')
Enter fullscreen mode Exit fullscreen mode

We can group everything together nicely, so it is clear the user variable is only used here.

tap(await User.query().latest().first(), user => {
    expect(user.name).toBe('test name')
    expect(user.bio).toBe('test bio')
})
Enter fullscreen mode Exit fullscreen mode

Discussion (2)

Collapse
baso53 profile image
Sebastijan Grabar • Edited on

This only works for mutable operations on data structures. Image you use the filter function on the array (or map or reduce).

const { tap } = require('taptaptap');

const arr = [1, 2, 3];
const mappedArr = tap(arr).map(val => val * 2);

mappedArr[0] === arr[0] // the value returned from the map function is the old array
Collapse
michi profile image
Michael Z Author

Yup, unnecessary in such cases.