The take function allows you to perform a sequence of operations on any object without needing to create intermediate variables and without needing to worry about null or undefined values.
import take from 'take-then';
const fourthLetterInUpperCase = string =>
take(string)
.then(string => string.toUpperCase())
.then(string => string[3])
.withDefault(😢);
fourthLetterInUpperCase('hello'); // 'L'
fourthLetterInUpperCase('foo'); // '😢'We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.
We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.
You're free to use this package (it's MIT-licensed), but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.
Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium.
The best postcards will get published on the open source page on our website.
take-then can be installed with yarn or npm:
yarn add take-thentake-then exposes one function: take. The take function decorates an object that lets us chain a series of operations on it.
The methods on the wrapped object are (T is the type of the wrapped object):
then performs an operation on the wrapped object if the object isn't null or undefined, and returns a new wrapped opject containing the transformed value.
const object = take('foo').then(string => string.toUpperCase());In the example, object contains FOO internally. Since object is a Wrapper, then calls can be chained.
Return the wrapped value.
const value = take('foo')
.then(string => string.toUpperCase())
.get();In the example, value equals "FOO".
Return the wrapped value, or the fallback if the wrapped value is null or undefined.
const value = take(['a', 'b'])
.then(chars => chars[2])
.withDefault('z');In the example, value equals "z", since chars[2] is undefined.
Returns true if the wrapped value isn't null or undefined.
Returns true if the wrapped value is null or undefined.
Log the value and (optionally) a message, and return the value in the wrapper. Useful for debugging chains.
take-then is great for refactoring processes with intermediate null or undefined checks into a clean & composable pipeline.
Consider a case where we want to retrieve a user's role by passing the user's name. Roles are object stored in a different array. Here's our setup:
const users = [
{ id: 1, name: 'Sebastian', role: 1 },
{ id: 2, name: 'Freek', role: 1 },
{ id: 3, name: 'Willem', role: 2 },
];
const roles = [
{ id: 1, name: 'Developer' },
{ id: 2, name: 'Designer' },
];Now for our first implementation.
const findRoleNameByUserName = name => {
const user = users.find(u => u.name === name);
const role = roles.find(r => r.id === user.role);
return role.name;
};There are some issues here. If either the user or the role isn't found, we'll have runtime errors, since we'd be trying to retrieve a property from something undefined (user.role and role.name are the dangerous parts here).
We can avoid this with early returns. Let's return an empty string in this case, since we're expecting a string in the first place.
const findRoleNameByUserName = name => {
const user = users.find(u => u.name === name);
if (! user) {
return '';
}
const role = roles.find(r => r.id === user.role);
if (! role) {
return '';
}
return role.name;
};Our code works, but it's not the prettiest thing... Time to refactor this to a single statement with take-then! Since take-then avoids calling a function when the wrapped object is null or undefined, we don't need to worry about those checks anymore—without reintroducing the potential runtime errors.
const findRoleNameByUserName = name =>
take(name)
.then(name => users.find(u => u.name === name))
.then(user => roles.find(r => r.id === user.role))
.then(role => role.name)
.withDefault('');Voila! Our chain won't throw any runtime errors, and if our value became null or undefined at any part, we'll return an empty string instead. We can make this even more readable by splitting our pipeline into bite-sized pieces instead of a chain of anonymous functions.
const findUserByName = name => users.find(u => u.name === name);
const findRoleForUser = user => roles.find(r => r.id === user.role);
const findRoleNameByUserName = name =>
take(name)
.then(findUserByName)
.then(findRoleForUser)
.then(role => role.name)
.withDefault('');Please see CHANGELOG for more information what has changed recently.
$ yarn testPlease see CONTRIBUTING for details.
If you discover any security related issues, please contact Freek Van der Herten instead of using the issue tracker.
Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.
The MIT License (MIT). Please see License File for more information.
