Yesterday, I tweeted about how often I encounter people opposed to using Lodash in their projects.
I'm frequently surprised how many people refuse to allow Lodash in their projects. I get it. However, I can't live without `_.get`. It's a life saver and prevents so much hassle guarding code. https://t.co/1gI4e1ZfGe
— Justin Noel (@calendee) June 13, 2019
Admittedly, importing an entire library to use a few functions is overkill in most cases. In those cases, you can install just the few Lodash methods you want. For example:
import get from 'lodash.get';
import has from 'lodash.has';
However, if you look at your package-lock.json
, you might find your project already has Lodash built into it whether you like it or not. If you're developing a React Native app, many of your dependencies are already importing the entire Lodash package.
Introduction to get
My favorite Lodash method is get
. It's indispensable for getting deeply nested data from JSON without having to add tons of guards around your code.
For example, (sorry about the uncreative fake data). I need to know whether I starred my own project:
Here's the original data:
const repo = {
id: 15812473,
node_id: "MDEwOlJlcG9zaXRvcnkxNTgxMjQ3Mw==",
name: "Adaptive-UIs",
owner: {
node_id: "MDQ6VXNlcjU3Mzc0",
other_suff: {
has_projects: true,
has_downloads: true,
has_wiki: true,
has_pages: false,
updated_at: "2014-01-10T23:10:12Z",
pushed_at: "2013-06-05T06:46:04Z"
}
},
html_url: "https://github.com/calendee/Adaptive-UIs"
};
Trying to get the value of a property that may not exist in another property that may not exist:
const starredByCalendee =
repo &&
repo.owner &&
repo.owner.other_suff &&
repo.owner.other_suff.starred_by &&
repo.owner.other_suff.starred_by.calendee
? repo.owner.other_suff.starred_by.calendee
: false;
console.log(`starredByCalendee = ${starredByCalendee}`);
To avoid potential errors if one level does not exist, you have to add tons of guards around the code. This gets really painful and hard to read.
With Lodash's get
, it's as simple as this:
const starredByCalendee = get("repo", "owner.other_suff.starred_by.calendee", false);
console.log(`starredByCalendee = ${starredByCalendee}`);
See how much easier that was? The code is now infinitely more readable and less prone to bugs and unexpected crashes.
Destructuring
Now, imagine you need to get several properties from a deeply nested object. You could access each one individually:
const has_projects = get(repo, "owner.other_suff.has_projects");
const has_downloads = get(repo, "owner.other_suff.has_downloads");
const has_wiki = get(repo, "owner.other_suff.has_wiki");
const has_fun = get(repo, "owner.other_suff.has_fun");
console.log("Individual Variables");
console.log(has_projects, has_downloads, has_wiki, has_fun);
However, you can just as easily destructure the returned object from get
:
const { updated_at, pushed_at, improved_at } = get(repo, "owner.other_suff");
console.log("Destructured Variables");
console.log(updated_at, pushed_at, improved_at);
Summary
As I tweeted, yes, you can roll your own utility function that does much of what Lodash get
can do. However, it will almost certainly not be as performant, feature rich, or well tested. For all this functionality, I'm willing to accept the cost of a 4kb import.
Example
Coming Soon To a TypeScript Near You!
FYI: This type of functionality already has been proposed for JavaScript in TC39. It's even possible to use it now with a Babel plugin. Unfortunately, TypeScript doesn't understand this syntax and you'll have to either ignore the code or wait until TypeScript supports it. Fortunately, TypeScript 3.7 should have this functionality.