What is remeda?
Remeda is a utility library for JavaScript and TypeScript that provides a collection of functions for working with arrays, objects, and other data types. It is designed to be a modern, functional alternative to libraries like Lodash, with a focus on immutability and type safety.
What are remeda's main functionalities?
Array Manipulation
Remeda provides a variety of functions for manipulating arrays, such as `filter`, `map`, and `reduce`. These functions can be composed using `R.pipe` to create complex transformations in a readable and functional style.
const arr = [1, 2, 3, 4, 5];
const result = R.pipe(
arr,
R.filter(x => x % 2 === 0),
R.map(x => x * 2)
);
console.log(result); // [4, 8]
Object Manipulation
Remeda includes functions for working with objects, such as `omit`, `pick`, and `merge`. These functions allow you to create new objects with specific properties removed, selected, or combined.
const obj = { a: 1, b: 2, c: 3 };
const result = R.omit(obj, ['b']);
console.log(result); // { a: 1, c: 3 }
Functional Programming
Remeda supports functional programming techniques, such as partial application and currying. The `partial` function allows you to create new functions with some arguments pre-filled, making it easier to create reusable and composable functions.
const add = (a, b) => a + b;
const add10 = R.partial(add, 10);
console.log(add10(5)); // 15
Type Safety
Remeda is designed with TypeScript in mind, providing type-safe functions that help catch errors at compile time. This ensures that your code is more robust and less prone to runtime errors.
const arr: number[] = [1, 2, 3, 4, 5];
const result = R.map(arr, x => x * 2);
console.log(result); // [2, 4, 6, 8, 10]
Other packages similar to remeda
lodash
Lodash is a popular utility library that provides a wide range of functions for working with arrays, objects, and other data types. While Lodash is more widely used and has a larger community, Remeda offers a more modern and functional approach with better TypeScript support.
ramda
Ramda is a functional programming library for JavaScript that emphasizes immutability and function composition. Like Remeda, Ramda provides a collection of functions for working with data in a functional style. However, Remeda is designed to be more type-safe and user-friendly for TypeScript users.
fp-ts
fp-ts is a library for functional programming in TypeScript. It provides a comprehensive set of tools for working with functional programming concepts, such as monads and functors. While fp-ts is more powerful and flexible, it has a steeper learning curve compared to Remeda.
Remeda
The first "data-first" and "data-last" utility library designed especially for TypeScript.
Installation
npm i remeda
yarn add remeda
Then in .js or .ts
import * as R from 'remeda';
Why Remeda?
There are no good utility libraries that work well with TypeScript. When working with Lodash or Ramda you must sometimes annotate types manually.
Remeda is written and tested in TypeScript and that means there won't be any problems with custom typings.
What's "data-first" and "data-last"?
Functional programming is nice, and it makes the code more readable. However there are situations where you don't need "pipes", and you want to call just a single function.
R.pick(obj, ['firstName', 'lastName']);
R.pick(['firstName', 'lastName'], obj);
_.pick(obj, ['firstName', 'lastName']);
In the above example, "data-first" approach is more natural and more programmer friendly because when you type the second argument, you get the auto-complete from IDE. It's not possible to get the auto-complete in Ramda because the data argument is not provided.
"data-last" approach is helpful when writing data transformations aka pipes.
const users = [
{name: 'john', age: 20, gender: 'm'},
{name: 'marry', age: 22, gender: 'f'},
{name: 'samara', age: 24, gender: 'f'},
{name: 'paula', age: 24, gender: 'f'},
{name: 'bill', age: 33, gender: 'm'},
]
R.pipe(
users,
R.filter(x => x.gender === 'f'),
R.groupBy(x => x.age),
);
R.pipe(
R.filter(x => x.gender === 'f'),
R.groupBy(x => x.age),
)(users)
_(users)
.filter(x => x.gender === 'f')
.groupBy(x => x.age)
.value()
_.flow(
_.filter(x => x.gender === 'f'),
_.groupBy(x => x.age),
)(users)
Mixing paradigms can be cumbersome in Lodash because it requires importing two different methods.
Remeda implements all methods in two versions, and the correct overload is picked based on the number of provided arguments.
The "data-last" version must always have one argument less than the "data-first" version.
R.pick(obj, ['firstName', 'lastName']);
R.pipe(obj, R.pick(['firstName', 'lastName']));
R.pick(['firstName', 'lastName'], obj);
R.pick(['firstName', 'lastName'])(obj);
Lazy evaluation
Many functions support lazy evaluation when using pipe
or createPipe
. These functions have a pipeable
tag in the documentation.
Lazy evaluation is not supported in Ramda and only partially supported in lodash.
const arr = [1, 2, 2, 3, 3, 4, 5, 6];
const result = R.pipe(
arr,
R.map(x => {
console.log('iterate', x);
return x;
}),
R.uniq(),
R.take(3)
);
Indexed version
Iterable functions have an extra property indexed
which is the same function with iterator (element, index, array)
.
const arr = [10, 12, 13, 3];
R.filter(arr, x => x % 2 === 0);
R.filter.indexed(arr, (x, i) => i % 2 === 0);
Remeda Design Goals
- The usage must be programmer friendly, and that's more important than following XYZ paradigm strictly.
- Manual annotation should never be required, and proper typings should infer everything. The only exception is the first function in
createPipe
. - E6 polyfill is required. Core methods are reused, and data structure (like Map/Set) are not re-implemented.
- The implementation of each function should be as minimal as possible. Tree-shaking is supported by default. (Do you know that
lodash.keyBy
has 14KB after minification?) - All functions are immutable, and there are no side-effects.
- Fixed number of arguments.
MIT