Eight (Groups of) Lodash Functions I Reach for the Most
Pearl Zeng-Yoders
Posted on March 1, 2022
Wanted to share some Lodash functions that I reach out to a lot either in our React frontend or Node backend. I find them handy and that they improve code readability.
1. lodash/get
Use case: Get a property or nested property from an object when the object or its properties are potentially undefined. Can also provide a default value if needed.
// Examples: get company and department properties of a person,
// variable `person` has the following type interface:
interface Person {
firstName: string;
lastName: string;
company?: {
name: string;
// ...other company props
department?: {
name: string;
// ...other department props
}
}
}
// Example 1: Get the name of the person's company,
// if undefined, give it ‘Company S’;
// Using syntax 1: use string to express props to look up
const companyName = get(person, 'company.name', 'Company S');
// Example 2: Get the name of the person's department,
// if undefined, give it ‘Department E’;
// Using syntax 2: use array of strings to express props to look up
cont departmentName = get(person, ['company', 'department', 'name'], 'Department E');
Both syntax allow the use of variables if the look up property name is a variable:
// syntax 1:
const somePropOfCompany = get(person, `company[${propName}]`);
// syntax 2:
const somePropOfCompany = get(person, ['company', propName]);
2. lodash/partition
, lodash/difference
, & lodash/intersection
Use case: I reach for these functions when needing to handle parts of an array differently.
lodash/partition
// Example: Given an array of items, handle featured items and the rest of the items differently,
// variable `item` has the following type interface:
interface Item {
name: string;
isFeatured: boolean;
category: 'Hobby' | 'Skill' | 'Other';
};
const itemList: Item[] = [
{
name: 'my hobby 1',
isFeatured: false,
category: 'Hobby',
},
{
name: 'my hobby 2',
isFeatured: true,
category: 'Hobby',
},
{
name: 'my skill 1',
isFeatured: true,
category: 'Skill',
},
{
name: 'my item 100',
isFeatured: false,
category: 'Other',
}
// ... more items like the above
];
// Use partition to get a list of featured items and a list of the rest of the items
const [featuredItems, restOfItems] = partition(itemList, { isFeatured: true });
// The second argument can also be a function instead of a property object,
// for example, partition a list of featured hobby items from the rest of the items
const [featuredHobbyItems, restOfItems] = partition(itemList,
item => item.isFeatured && item.category === 'Hobby');
lodash/difference
// Example: Given a list of incoming members and a list of members from user input,
// get the members to add
const currentMembers = [
// ...an array of existing members from the API
];
const incomingMembers = [
// ...an array of new members from the form input
];
const membersToAdd = difference(incomingMembers, currentMembers);
lodash/intersection
// Example: given the same member list from the above, get the members to remove
const membersToRemove = intersection(currentMembers, incomingMembers);
3. lodash/keyBy
& lodash/groupBy
Use case: Build a lookup – keyBy
uses one object property as the key, and groupBy
groups array items with the same keys into an array under that key.
lodash/keyBy
// Example: Given a list of people with the following type interface,
// get a lookup of people by id
interface Person {
id: string;
firstName: string;
lastName: string;
companyName: string;
};
const people: person[] = [
// ...list of people
];
const peopleLookup = keyBy(people, 'id');
// Resulting interface:
interface PeopleLookup {
[id: string]: Person;
};
lodash/groupBy
// Example: Given a list of people like the above,
// get a lookup of people by company name
const peopleByCompany = groupBy(people, 'companyName');
// Resulting interface:
interface PeopleByCompany {
[companyName: string]: Person[];
};
4. lodash/compact
& lodash/isEmpty
Use case: Make sure intended operations don’t happen on falsey items.
lodash/compact
// Example: Given a list of people with the following interface,
// get a list of profile photo urls
interface Person {
firstName: string;
lastName: string;
profilePictureUrl?: string;
};
const people: Person[] = [
// ...list of people
];
const profilePictureUrls = compact(people.map(p => p.profilePictureUrl));
// Using compact here will get rid of any undefined, null, or empty values
lodash/isEmpty
// Example 1: Given the people list like the above,
// call the API to upload the photos if profilePictureUrls is not empty
if (!isEmpty(profilePictureUrls)) {
// call the API
}; // Can also be accomplished by checking array length
// Example 2: Given an object of props to update for a person,
// call the person update endpoint if there are items to update
interface PersonUpdate {
email?: string;
phoneNumber?: string;
company?: {
name?: string;
department?: string;
};
// ...many more properties
}
if (!isEmpty(PersonUpdate)) {
// call the person update endpoint
}
5. lodash/pick
, lodash/omit
, lodash/uniq
, & lodash/isEqual
Use case: Grab intended properties to send to the API or for display on the UI.
// Examples: Given updatePersonRequest,
const validPersonProps = ['firstName', 'lastName', 'email', 'number'];
// Use pick to grab valid props to send to the updatePerson API endpoint
await updatePerson(pick(updatePersonRequest, validPersonProps));
const propsToSendSeparately = ['profilePhotoUrl', 'coverPhotoUrl'];
// Use omit to omit properties that are handled via a different endpoint
await updatePerson(omit(updatePersonRequest, propsToSendSeparately));
// Use isEqual to decide whether to call the updateEndpoint,
// it performs a deep comparison
if (!isEqual(currentPersonValue, editedPersonValue)) {
// call the update endpoint
};
// Let's say for every companyName, we need to create a company profile page
const personList = [
{
firstName: 'John'
lastName: 'Doe',
companyName: 'Company A'
},
{
firstName: 'Sara'
lastName: 'Smith',
companyName: 'Company A'
},
{
firstName: 'James'
lastName: 'Bond',
companyName: 'Company B'
},
// ...more person objects like the above
];
// Use uniq to avoid duplicated company page creation
const namesForCompanyPageCreation = uniq(personList.map(p => p.companyName));
6. lodash/sortBy
& lodash/orderBy
Use case: Sort and order array items.
sortBy
sorts items in ascending order, and orderBy
allows specifying the sort order.
// Examples:
// Use sortBy to sort timezones in UTC offset,
// and if offset is the same, sort by displayName
const timezonesOrderedByUtcOffset = sortBy(timezones, [
tzItem => tz.utcOffect,
'displayName'
]); // This array accepts both a callback and a property name
// Get the latest blog post by first using orderBy to order posts in descending order
const [latestBlogPost] = orderBy(blogposts, 'createdAt', 'desc');
// The second and third arguments can both be arrays as well, e.g.
// Order the blog posts by descending order for creation date,
// and ascending order for edited date
const orderedPosts = orderBy(blogposts, ['createdAt', 'editedAt'], ['desc', 'asc']);
7. lodash/chunk
Use case: Chunk items when inserting into the sql database to avoid inserting a big amount of data at once.
// Example: Insert over 10,000 people into the person table.
// Chunk the data into 500 chunks first and then insert with a custom insertMany function
const chunkedPeopleData = chunk(peopleData, 500);
await Promise.all(chunkedPeopleData.map(data =>
insertMany('person', data)
));
8. lodash/sumBy
Decided to use sumBy
to wrap up the post ;)
Use case: Get the sum.
// Example: Get total post reads
interface Post {
name: string;
viewCount: number;
}
const posts: Post[] = [
// ...a list of posts
];
const totalPostReads = sumBy(posts, 'viewCount');
That’s It
Those are the Lodash functions I normally reach for, along with their examples. There are debates on whether to use Lodash, given the weight it adds to the application. Additionally, newer versions of Javascript can accomplish a lot more functions that Lodash was trying to simplify. One thing came to mind was flat()
that was introduced with ES2019. It handles deep flatten nicely:
const arr = [0, 1, 2, [[[3, 4]]], [[[[5, 6]], [7, 8]]]];
// To turn the above array into [1, 2, 3, 4, 5, 6, 7, 8]:
// Flat deep with ES2019
const flatArr = arr.flat(Infinity);
// Flat deep with lodash
const loFlatArr = flattenDeep(arr);
And many of the above use cases can be achieved by Javascript native function reduce
, but I find the Lodash functions provide more communicative APIs. And to reduce (😉) the impact of library weight, I would only import the needed modules:
// Instead of this:
import { isEmpty } from 'lodash';
// Do this:
import isEmpty from 'lodash/isEmpty';
Let me know your thoughts in the comments. Happy Lodashing!
Posted on March 1, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.