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!
Top comments (0)