0.0.1 • Published 6 years ago

comp-check v0.0.1

Weekly downloads
3
License
MIT
Repository
github
Last release
6 years ago

comp-check

Build Status Coverage Status npm version

A Javascript library to help with null checking in functional composition

Example Usage

Suppose we have the following data

const usersById = {
  123: {
    id: 123,
    firstName: 'John',
    lastName: 'Smith',
    father: 456,
  },
  456: {
    id: 123,
    firstName: 'Fred',
    lastName: 'Smith',
    father: null,
  }
};

and the following functions:

const userFromId = id => usersById[id] ? usersById[id] : null;

const father = user => userFromId(user.father);

const fullName = user => {
  const { firstName, lastName } = user;
  if (firstName === undefined || lastName === undefined) {
    return null
  }
  return `${firstName} ${lastName}`;
};

And suppose we want to compose these functions into a pure function that returns the full name of a user's father given the user's id.

The following won't work, because it's impure:

const pipe = require('lodash/fp/pipe');

const fatherFullName = pipe(
  userFromId,
  father,
  fullName
);

It's impure because it throws errors that it doesn't catch, for example, when userFromId or father returns null:

fatherFullName(123); // Fred Smith
fatherFullName(789); // TypeError: Cannot read property 'father' of null
fatherFullName(456); // TypeError: Cannot destructure property `firstName` of 'undefined' or 'null'.

To achieve purity we need to handle these null values without uncaught errors.

In effect, we need something along the following lines:

const pipe = require('lodash/fp/pipe');

const fatherFullName = pipe(
   userFromId,
   value => {
     if (value === null) return null;
     return father(value);
   },
   value => {
     if (value === null) return null;
     return fullName(value);
   }
);

fatherFullName(123); // Fred Smith
fatherFullName(789); // null
fatherFullName(456); // null

But achieving purity in this way exposes repetitive null checking details that distract from the main positive focus of our function. Using comp-check, we can achieve the same result without all the mess:

const { always, map, maybe } = require('comp-check');
const pipe = require('lodash/fp/pipe');
const identity = require('lodash/fp/identity');

const fatherFullName = pipe(
  maybe, // wraps our argument in a new object called a "Maybe"
  map(userFromId), // applies userFromId to our argument if not null
  map(father), // applies father to the result if not null
  map(fullName),  // does the same but with fullName
  always(identity) // returns our final result, null or not
);