Documentation

Intro

Welcome to the Remeda documentation and API reference. Below, you’ll find the complete reference for all functions exported by Remeda.

Previous Versions

Are you using version 1.x.x? Visit our migration guide to help you transition to the latest version.


Determines whether all predicates returns true for the input data.

Data First
allPass(data, fns);
const isDivisibleBy3 = (x: number) => x % 3 === 0;
const isDivisibleBy4 = (x: number) => x % 4 === 0;
const fns = [isDivisibleBy3, isDivisibleBy4];
allPass(12, fns); // => true
allPass(8, fns); // => false
Data Last
allPass(fns)(data);
const isDivisibleBy3 = (x: number) => x % 3 === 0;
const isDivisibleBy4 = (x: number) => x % 4 === 0;
const fns = [isDivisibleBy3, isDivisibleBy4];
allPass(fns)(12); // => true
allPass(fns)(8); // => false

Determines whether any predicate returns true for the input data.

Data First
anyPass(data, fns);
const isDivisibleBy3 = (x: number) => x % 3 === 0;
const isDivisibleBy4 = (x: number) => x % 4 === 0;
const fns = [isDivisibleBy3, isDivisibleBy4];
anyPass(8, fns); // => true
anyPass(11, fns); // => false
Data Last
anyPass(fns)(data);
const isDivisibleBy3 = (x: number) => x % 3 === 0;
const isDivisibleBy4 = (x: number) => x % 4 === 0;
const fns = [isDivisibleBy3, isDivisibleBy4];
anyPass(fns)(8); // => true
anyPass(fns)(11); // => false

Split an array into groups the length of size. If array can't be split evenly, the final chunk will be the remaining elements.

Data First
chunk(array, size);
chunk(["a", "b", "c", "d"], 2); // => [['a', 'b'], ['c', 'd']]
chunk(["a", "b", "c", "d"], 3); // => [['a', 'b', 'c'], ['d']]
Data Last
chunk(size)(array);
chunk(2)(["a", "b", "c", "d"]); // => [['a', 'b'], ['c', 'd']]
chunk(3)(["a", "b", "c", "d"]); // => [['a', 'b', 'c'], ['d']]

Merge two or more arrays. This method does not change the existing arrays, but instead returns a new array, even if the other array is empty.

Data First
concat(data, other);
concat([1, 2, 3], ["a"]); // [1, 2, 3, 'a']
Data Last
concat(arr2)(arr1);
concat(["a"])([1, 2, 3]); // [1, 2, 3, 'a']

Categorize and count elements in an array using a defined callback function. The callback function is applied to each element in the array to determine its category and then counts how many elements fall into each category.

Data First
countBy(data, categorizationFn);
countBy(["a", "b", "c", "B", "A", "a"], toLowerCase()); //=> { a: 3, b: 2, c: 1 }
Data Last
countBy(categorizationFn)(data);
pipe(["a", "b", "c", "B", "A", "a"], countBy(toLowerCase())); //=> { a: 3, b: 2, c: 1 }
difference
Lazy GitHub View source on GitHub

Excludes the values from other array. The output maintains the same order as the input. The inputs are treated as multi-sets/bags (multiple copies of items are treated as unique items).

Data First
difference(data, other);
difference([1, 2, 3, 4], [2, 5, 3]); // => [1, 4]
difference([1, 1, 2, 2], [1]); // => [1, 2, 2]
Data First
difference(other)(data);
pipe([1, 2, 3, 4], difference([2, 5, 3])); // => [1, 4]
pipe([1, 1, 2, 2], difference([1])); // => [1, 2, 2]
differenceWith
Lazy GitHub View source on GitHub

Excludes the values from other array. Elements are compared by custom comparator isEquals.

Data First
differenceWith(data, other, isEqual);
differenceWith(
  [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }],
  [2, 5, 3],
  ({ a }, b) => a === b,
); //=> [{ a: 1 }, { a: 4 }]
Data Last
differenceWith(other, isEqual)(data);
pipe(
  [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }, { a: 5 }, { a: 6 }],
  differenceWith([2, 3], ({ a }, b) => a === b),
); //=> [{ a: 1 }, { a: 4 }, { a: 5 }, { a: 6 }]

Removes first n elements from the array.

Data First
drop(array, n);
drop([1, 2, 3, 4, 5], 2); // => [3, 4, 5]
Data Last
drop(n)(array);
drop(2)([1, 2, 3, 4, 5]); // => [3, 4, 5]
dropFirstBy
GitHub View source on GitHub

Drop the first n items from data based on the provided ordering criteria. This allows you to avoid sorting the array before dropping the items. The complexity of this function is O(Nlogn) where N is the length of the array.

For the opposite operation (to keep n elements) see takeFirstBy.

Data First
dropFirstBy(data, n, ...rules);
dropFirstBy(["aa", "aaaa", "a", "aaa"], 2, (x) => x.length); // => ['aaa', 'aaaa']
Data Last
dropFirstBy(n, ...rules)(data);
pipe(
  ["aa", "aaaa", "a", "aaa"],
  dropFirstBy(2, (x) => x.length),
); // => ['aaa', 'aaaa']

Removes last n elements from the array.

Data First
dropLast(array, n);
dropLast([1, 2, 3, 4, 5], 2); // => [1, 2, 3]
Data Last
dropLast(n)(array);
dropLast(2)([1, 2, 3, 4, 5]); // => [1, 2, 3]
dropLastWhile
GitHub View source on GitHub

Removes elements from the end of the array until the predicate returns false.

The predicate is applied to each element in the array starting from the end and moving towards the beginning, until the predicate returns false. The returned array includes elements from the beginning of the array, up to and including the element that produced false for the predicate.

Data First
dropLastWhile(data, predicate);
dropLastWhile([1, 2, 10, 3, 4], (x) => x < 10); // => [1, 2, 10]
Data Last
dropLastWhile(predicate)(data);
pipe(
  [1, 2, 10, 3, 4],
  dropLastWhile((x) => x < 10),
); // => [1, 2, 10]

Removes elements from the beginning of the array until the predicate returns false.

The predicate is applied to each element in the array, until the predicate returns false. The returned array includes the rest of the elements, starting with the element that produced false for the predicate.

Data First
dropWhile(data, predicate);
dropWhile([1, 2, 10, 3, 4], (x) => x < 10); // => [10, 3, 4]
Data Last
dropWhile(predicate)(data);
pipe(
  [1, 2, 10, 3, 4],
  dropWhile((x) => x < 10),
); // => [10, 3, 4]

Creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function. Equivalent to Array.prototype.filter.

Data First
filter(data, predicate);
filter([1, 2, 3], (x) => x % 2 === 1); // => [1, 3]
Data Last
filter(predicate)(data);
pipe(
  [1, 2, 3],
  filter((x) => x % 2 === 1),
); // => [1, 3]

Returns the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned.

Similar functions:

  • findLast - If you need the last element that satisfies the provided testing function.
  • findIndex - If you need the index of the found element in the array.
  • indexOf - If you need to find the index of a value.
  • includes - If you need to find if a value exists in an array.
  • some - If you need to find if any element satisfies the provided testing function.
  • filter - If you need to find all elements that satisfy the provided testing function.
Data First
find(data, predicate);
find([1, 3, 4, 6], (n) => n % 2 === 0); // => 4
Data Last
find(predicate)(data);
pipe(
  [1, 3, 4, 6],
  find((n) => n % 2 === 0),
); // => 4

Returns the index of the first element in an array that satisfies the provided testing function. If no elements satisfy the testing function, -1 is returned.

See also the find method, which returns the first element that satisfies the testing function (rather than its index).

Data First
findIndex(data, predicate);
findIndex([1, 3, 4, 6], (n) => n % 2 === 0); // => 2
Data Last
findIndex(predicate)(data);
pipe(
  [1, 3, 4, 6],
  findIndex((n) => n % 2 === 0),
); // => 2

Iterates the array in reverse order and returns the value of the first element that satisfies the provided testing function. If no elements satisfy the testing function, undefined is returned.

Similar functions:

  • find - If you need the first element that satisfies the provided testing function.
  • findLastIndex - If you need the index of the found element in the array.
  • lastIndexOf - If you need to find the index of a value.
  • includes - If you need to find if a value exists in an array.
  • some - If you need to find if any element satisfies the provided testing function.
  • filter - If you need to find all elements that satisfy the provided testing function.
Data First
findLast(data, predicate);
findLast([1, 3, 4, 6], (n) => n % 2 === 1); // => 3
Data Last
findLast(predicate)(data);
pipe(
  [1, 3, 4, 6],
  findLast((n) => n % 2 === 1),
); // => 3
findLastIndex
GitHub View source on GitHub

Iterates the array in reverse order and returns the index of the first element that satisfies the provided testing function. If no elements satisfy the testing function, -1 is returned.

See also findLast which returns the value of last element that satisfies the testing function (rather than its index).

Data First
findLastIndex(data, predicate);
findLastIndex([1, 3, 4, 6], (n) => n % 2 === 1); // => 1
Data Last
findLastIndex(fn)(items);
pipe(
  [1, 3, 4, 6],
  findLastIndex((n) => n % 2 === 1),
); // => 1

Gets the first element of array.

Data First
first(array);
first([1, 2, 3]); // => 1
first([]); // => undefined
Data Last
first()(array);
pipe(
  [1, 2, 4, 8, 16],
  filter((x) => x > 3),
  first(),
  (x) => x + 1,
); // => 5

Find the first element in the array that adheres to the order rules provided. This is a superset of what a typical maxBy or minBy function would do as it allows defining "tie-breaker" rules when values are equal, and allows comparing items using any logic. This function is equivalent to calling first(sortBy(...)) but runs at O(n) instead of O(nlogn).

Use nthBy if you need an element other that the first, or takeFirstBy if you more than just the first element.

Data First
firstBy(data, ...rules);
const max = firstBy([1, 2, 3], [identity(), "desc"]); // => 3;
const min = firstBy([1, 2, 3], identity()); // => 1;

const data = [{ a: "a" }, { a: "aa" }, { a: "aaa" }] as const;
const maxBy = firstBy(data, [(item) => item.a.length, "desc"]); // => { a: "aaa" };
const minBy = firstBy(data, (item) => item.a.length); // => { a: "a" };

const data = [
  { type: "cat", size: 1 },
  { type: "cat", size: 2 },
  { type: "dog", size: 3 },
] as const;
const multi = firstBy(data, prop("type"), [prop("size"), "desc"]); // => {type: "cat", size: 2}
Data Last
firstBy(...rules)(data);
const max = pipe([1, 2, 3], firstBy([identity(), "desc"])); // => 3;
const min = pipe([1, 2, 3], firstBy(identity())); // => 1;

const data = [{ a: "a" }, { a: "aa" }, { a: "aaa" }] as const;
const maxBy = pipe(data, firstBy([(item) => item.a.length, "desc"])); // => { a: "aaa" };
const minBy = pipe(
  data,
  firstBy((item) => item.a.length),
); // => { a: "a" };

const data = [
  { type: "cat", size: 1 },
  { type: "cat", size: 2 },
  { type: "dog", size: 3 },
] as const;
const multi = pipe(data, firstBy(prop("type"), [prop("size"), "desc"])); // => {type: "cat", size: 2}

Creates a new array with all sub-array elements concatenated into it recursively up to the specified depth. Equivalent to the built-in Array.prototype.flat method.

Data First
flat(data);
flat(data, depth);
flat([[1, 2], [3, 4], [5], [[6]]]); // => [1, 2, 3, 4, 5, [6]]
flat([[[1]], [[2]]], 2); // => [1, 2]
Data Last
flat()(data);
flat(depth)(data);
pipe([[1, 2], [3, 4], [5], [[6]]], flat()); // => [1, 2, 3, 4, 5, [6]]
pipe([[[1]], [[2]]], flat(2)); // => [1, 2]
flatMap
Lazy GitHub View source on GitHub

Returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level. It is identical to a map followed by a flat of depth 1 (flat(map(data, ...args))), but slightly more efficient than calling those two methods separately. Equivalent to Array.prototype.flatMap.

Data First
flatMap(data, callbackfn);
flatMap([1, 2, 3], (x) => [x, x * 10]); // => [1, 10, 2, 20, 3, 30]
Data Last
flatMap(callbackfn)(data);
pipe(
  [1, 2, 3],
  flatMap((x) => [x, x * 10]),
); // => [1, 10, 2, 20, 3, 30]
forEach
Lazy GitHub View source on GitHub

Executes a provided function once for each array element. Equivalent to Array.prototype.forEach.

The dataLast version returns the original array (instead of not returning anything (void)) to allow using it in a pipe. When not used in a pipe the returned array is equal to the input array (by reference), and not a shallow copy of it!

Data First
forEach(data, callbackfn);
forEach([1, 2, 3], (x) => {
  console.log(x);
});
Data Last
forEach(callbackfn)(data);
pipe(
  [1, 2, 3],
  forEach((x) => {
    console.log(x);
  }),
); // => [1, 2, 3]

Groups the elements of a given iterable according to the string values returned by a provided callback function. The returned object has separate properties for each group, containing arrays with the elements in the group. Unlike the built in Object.groupBy this function also allows the callback to return undefined in order to exclude the item from being added to any group.

If you are grouping objects by a property of theirs (e.g. groupBy(data, ({ myProp }) => myProp) or groupBy(data, prop('myProp'))) consider using groupByProp (e.g. groupByProp(data, 'myProp')) instead, as it would provide better typing.

Data First
groupBy(data, callbackfn);
groupBy([{ a: "cat" }, { a: "dog" }] as const, prop("a")); // => {cat: [{a: 'cat'}], dog: [{a: 'dog'}]}
groupBy([0, 1], (x) => (x % 2 === 0 ? "even" : undefined)); // => {even: [0]}
Data Last
groupBy(callbackfn)(data);
pipe([{ a: "cat" }, { a: "dog" }] as const, groupBy(prop("a"))); // => {cat: [{a: 'cat'}], dog: [{a: 'dog'}]}
pipe(
  [0, 1],
  groupBy((x) => (x % 2 === 0 ? "even" : undefined)),
); // => {even: [0]}
groupByProp
GitHub View source on GitHub

Groups the elements of an array of objects based on the values of a specified property of those objects. The result would contain a property for each unique value of the specific property, with it's value being the input array filtered to only items that have that property set to that value. For any object where the property is missing, or if it's value is undefined the item would be filtered out.

The grouping property is enforced at the type level to exist in at least one item and to never have a value that cannot be used as an object key (e.g. it must be PropertyKey | undefined).

The resulting arrays are filtered with the prop and it's value as a type-guard, effectively narrowing the items in each output arrays. This means that when the grouping property is the discriminator of a discriminated union type each output array would contain just the subtype for that value.

If you need more control over the grouping you should use groupBy instead.

Data First
groupByProp(data, prop);
const result = groupByProp(
  //  ^? { cat: [{ a: 'cat' }], dog: [{ a: 'dog' }] }
  [{ a: "cat" }, { a: "dog" }] as const,
  "a",
);
Data Last
groupByProp(prop)(data);
const result = pipe(
  //  ^? { cat: [{ a: 'cat' }], dog: [{ a: 'dog' }] }
  [{ a: "cat" }, { a: "dog" }] as const,
  groupByProp("a"),
);

Checks if the given array has at least the defined number of elements. When the minimum used is a literal (e.g. 3) the output is refined accordingly so that those indices are defined when accessing the array even when using typescript's 'noUncheckedIndexAccess'.

Data First
hasAtLeast(data, minimum);
hasAtLeast([], 4); // => false

const data: number[] = [1, 2, 3, 4];
hasAtLeast(data, 1); // => true
data[0]; // 1, with type `number`
Data Last
hasAtLeast(minimum)(data);
pipe([], hasAtLeast(4)); // => false

const data = [[1, 2], [3], [4, 5]];
pipe(
  data,
  filter(hasAtLeast(2)),
  map(([, second]) => second),
); // => [2,5], with type `number[]`

Converts a list of objects into an object indexing the objects by the given key.

There are several other functions that could be used to build an object from an array:

  • fromKeys - Builds an object from an array of keys and a mapper for values.
  • pullObject - Builds an object from an array of items with mappers for both keys and values.
  • fromEntries - Builds an object from an array of key-value pairs. Refer to the docs for more details.
Data First
indexBy(array, fn);
indexBy(["one", "two", "three"], (x) => x.length); // => {3: 'two', 5: 'three'}
Data Last
indexBy(fn)(array);
pipe(
  ["one", "two", "three"],
  indexBy((x) => x.length),
); // => {3: 'two', 5: 'three'}
intersection
Lazy GitHub View source on GitHub

Returns a list of elements that exist in both array. The output maintains the same order as the input. The inputs are treated as multi-sets/bags (multiple copies of items are treated as unique items).

Data First
intersection(data, other);
intersection([1, 2, 3], [2, 3, 5]); // => [2, 3]
intersection([1, 1, 2, 2], [1]); // => [1]
Data Last
intersection(other)(data);
pipe([1, 2, 3], intersection([2, 3, 5])); // => [2, 3]
pipe([1, 1, 2, 2], intersection([1])); // => [1]
intersectionWith
Lazy GitHub View source on GitHub

Returns a list of intersecting values based on a custom comparator function that compares elements of both arrays.

Data First
intersectionWith(array, other, comparator);
intersectionWith(
  [
    { id: 1, name: "Ryan" },
    { id: 3, name: "Emma" },
  ],
  [3, 5],
  (a, b) => a.id === b,
); // => [{ id: 3, name: 'Emma' }]
Data Last
intersectionWith(other, comparator)(array);
intersectionWith(
  [3, 5],
  (a, b) => a.id === b,
)([
  { id: 1, name: "Ryan" },
  { id: 3, name: "Emma" },
]); // => [{ id: 3, name: 'Emma' }]

Joins the elements of the array by: casting them to a string and concatenating them one to the other, with the provided glue string in between every two elements.

When called on a tuple and with stricter item types (union of literal values, the result is strictly typed to the tuples shape and it's item types).

Data First
join(data, glue);
join([1, 2, 3], ","); // => "1,2,3" (typed `string`)
join(["a", "b", "c"], ""); // => "abc" (typed `string`)
join(["hello", "world"] as const, " "); // => "hello world" (typed `hello world`)
Data Last
join(glue)(data);
pipe([1, 2, 3], join(",")); // => "1,2,3" (typed `string`)
pipe(["a", "b", "c"], join("")); // => "abc" (typed `string`)
pipe(["hello", "world"] as const, join(" ")); // => "hello world" (typed `hello world`)

Gets the last element of array.

Data First
last(array);
last([1, 2, 3]); // => 3
last([]); // => undefined
Data Last
last()(array);
pipe(
  [1, 2, 4, 8, 16],
  filter((x) => x > 3),
  last(),
  (x) => x + 1,
); // => 17

Counts values of the collection or iterable.

Data First
length(array);
length([1, 2, 3]); // => 3
Data Last
length()(array);
pipe([1, 2, 3], length()); // => 3

Creates a new array populated with the results of calling a provided function on every element in the calling array. Equivalent to Array.prototype.map.

Data First
map(data, callbackfn);
map([1, 2, 3], multiply(2)); // => [2, 4, 6]
map([0, 0], add(1)); // => [1, 1]
map([0, 0], (value, index) => value + index); // => [0, 1]
Data Last
map(callbackfn)(data);
pipe([1, 2, 3], map(multiply(2))); // => [2, 4, 6]
pipe([0, 0], map(add(1))); // => [1, 1]
pipe(
  [0, 0],
  map((value, index) => value + index),
); // => [0, 1]

Map each element of an array into an object using a defined mapper that converts each item into an object entry (a tuple of [<key>, <value>]).

There are several other functions that could be used to build an object from an array:

  • fromKeys - Builds an object from an array of keys and a mapper for values.
  • indexBy - Builds an object from an array of values and a mapper for keys.
  • pullObject - Builds an object from an array of items with a mapper for values and another mapper for keys.
  • fromEntries - Builds an object from an array of key-value pairs.

Warning: We strongly advise against using this function unless it is used with a huge input array and your app has stringent memory/gc constraints. We recommend that in most cases you should use pullObject, or the composition fromEntries(map(array, fn)). This function will be deprecated and removed in future versions of the library!

Data First
mapToObj(array, fn);
mapToObj([1, 2, 3], (x) => [String(x), x * 2]); // => {1: 2, 2: 4, 3: 6}
Data Last
mapToObj(fn)(array);
pipe(
  [1, 2, 3],
  mapToObj((x) => [String(x), x * 2]),
); // => {1: 2, 2: 4, 3: 6}
mapWithFeedback
Lazy GitHub View source on GitHub

Applies a function on each element of the array, using the result of the previous application, and returns an array of the successively computed values.

Data First
mapWithFeedback(data, callbackfn, initialValue);
mapWithFeedback([1, 2, 3, 4, 5], (prev, x) => prev + x, 100); // => [101, 103, 106, 110, 115]
Data Last
mapWithFeedback(callbackfn, initialValue)(data);
pipe(
  [1, 2, 3, 4, 5],
  mapWithFeedback((prev, x) => prev + x, 100),
); // => [101, 103, 106, 110, 115]

Returns the mean of the elements of an array using the provided predicate.

Data First
meanBy(array, fn);
meanBy([{ a: 5 }, { a: 1 }, { a: 3 }], (x) => x.a); // 3
Data Last
meanBy(fn)(array);
pipe(
  [{ a: 5 }, { a: 1 }, { a: 3 }],
  meanBy((x) => x.a),
); // 3

Merges a list of objects into a single object.

Data First
mergeAll(objects);
mergeAll([{ a: 1, b: 1 }, { b: 2, c: 3 }, { d: 10 }]); // => { a: 1, b: 2, c: 3, d: 10 }
mergeAll([]); // => {}

Retrieves the element that would be at the given index if the array were sorted according to specified rules. This function uses the QuickSelect algorithm running at an average complexity of O(n). Semantically it is equivalent to sortBy(data, ...rules).at(index) which would run at O(nlogn).

See also firstBy which provides an even more efficient algorithm and a stricter return type, but only for index === 0. See takeFirstBy to get all the elements up to and including index.

Data First
nthBy(data, index, ...rules);
nthBy([2, 1, 4, 5, 3], 2, identity()); // => 3
Data Last
nthBy(index, ...rules)(data);
pipe([2, 1, 4, 5, 3], nthBy(2, identity())); // => 3

Returns the first and only element of array, or undefined otherwise.

Data First
only(array);
only([]); // => undefined
only([1]); // => 1
only([1, 2]); // => undefined
Data Last
only()(array);
pipe([], only()); // => undefined
pipe([1], only()); // => 1
pipe([1, 2], only()); // => undefined

Splits a collection into two groups, the first of which contains elements the predicate type guard passes, and the second one containing the rest.

Data First
partition(data, predicate);
partition(["one", "two", "forty two"], (x) => x.length === 3); // => [['one', 'two'], ['forty two']]
Data Last
partition(predicate)(data);
pipe(
  ["one", "two", "forty two"],
  partition((x) => x.length === 3),
); // => [['one', 'two'], ['forty two']]

Returns a list of numbers from start (inclusive) to end (exclusive).

Data First
range(start, end);
range(1, 5); // => [1, 2, 3, 4]
Data Last
range(end)(start);
range(5)(1); // => [1, 2, 3, 4]

Calculates the rank of an item in an array based on rules. The rank is the position where the item would appear in the sorted array. This function provides an efficient way to determine the rank in O(n) time, compared to O(nlogn) for the equivalent sortedIndex(sortBy(data, ...rules), item).

Data First
rankBy(data, item, ...rules);
const DATA = [{ a: 5 }, { a: 1 }, { a: 3 }] as const;
rankBy(DATA, 0, prop("a")); // => 0
rankBy(DATA, 1, prop("a")); // => 1
rankBy(DATA, 2, prop("a")); // => 1
rankBy(DATA, 3, prop("a")); // => 2
Data Last
rankBy(item, ...rules)(data);
const DATA = [{ a: 5 }, { a: 1 }, { a: 3 }] as const;
pipe(DATA, rankBy(0, prop("a"))); // => 0
pipe(DATA, rankBy(1, prop("a"))); // => 1
pipe(DATA, rankBy(2, prop("a"))); // => 1
pipe(DATA, rankBy(3, prop("a"))); // => 2

Executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value. Equivalent to Array.prototype.reduce.

Data First
reduce(data, callbackfn, initialValue);
reduce([1, 2, 3, 4, 5], (acc, x) => acc + x, 100); // => 115
Data Last
reduce(fn, initialValue)(array);
pipe(
  [1, 2, 3, 4, 5],
  reduce((acc, x) => acc + x, 100),
); // => 115

Reverses array.

Data First
reverse(arr);
reverse([1, 2, 3]); // [3, 2, 1]
Data Last
reverse()(array);
reverse()([1, 2, 3]); // [3, 2, 1]

Returns a random subset of size sampleSize from array.

Maintains and infers most of the typing information that could be passed along to the output. This means that when using tuples, the output will be a tuple too, and when using literals, those literals would be preserved.

The items in the result are kept in the same order as they are in the input. If you need to get a shuffled response you can pipe the shuffle function after this one.

Data First
sample(array, sampleSize);
sample(["hello", "world"], 1); // => ["hello"] // typed string[]
sample(["hello", "world"] as const, 1); // => ["world"] // typed ["hello" | "world"]
Data Last
sample(sampleSize)(array);
sample(1)(["hello", "world"]); // => ["hello"] // typed string[]
sample(1)(["hello", "world"] as const); // => ["world"] // typed ["hello" | "world"]

Shuffles the input array, returning a new array with the same elements in a random order.

Data First
shuffle(array);
shuffle([4, 2, 7, 5]); // => [7, 5, 4, 2]
Data Last
shuffle()(array);
pipe([4, 2, 7, 5], shuffle()); // => [7, 5, 4, 2]

Sorts an array. The comparator function should accept two values at a time and return a negative number if the first value is smaller, a positive number if it's larger, and zero if they are equal. Sorting is based on a native sort function.

Data First
sort(items, cmp);
sort([4, 2, 7, 5], (a, b) => a - b); // => [2, 4, 5, 7]
Data Last
sort(cmp)(items);
pipe(
  [4, 2, 7, 5],
  sort((a, b) => a - b),
); // => [2, 4, 5, 7]

Sorts data using the provided ordering rules. The sort is done via the native Array.prototype.sort but is performed on a shallow copy of the array to avoid mutating the original data.

There are several other functions that take order rules and bypass the need to sort the array first (in O(nlogn) time):

  • firstBy === first(sortBy(data, ...rules)), O(n).
  • takeFirstBy === take(sortBy(data, ...rules), k), O(nlogk).
  • dropFirstBy === drop(sortBy(data, ...rules), k), O(nlogk).
  • nthBy === sortBy(data, ...rules).at(k), O(n).
  • rankBy === sortedIndex(sortBy(data, ...rules), item), O(n). Refer to the docs for more details.
Data First
sortBy(data, ...rules);
sortBy([{ a: 1 }, { a: 3 }, { a: 7 }, { a: 2 }], prop("a")); // => [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 7 }]
sortBy(
  [
    { color: "red", weight: 2 },
    { color: "blue", weight: 3 },
    { color: "green", weight: 1 },
    { color: "purple", weight: 1 },
  ],
  [prop("weight"), "asc"],
  prop("color"),
); // => [
//   {color: 'green', weight: 1},
//   {color: 'purple', weight: 1},
//   {color: 'red', weight: 2},
//   {color: 'blue', weight: 3},
// ]
Data Last
sortBy(...rules)(data);
pipe([{ a: 1 }, { a: 3 }, { a: 7 }, { a: 2 }], sortBy(prop("a"))); // => [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 7 }]
sortedIndex
GitHub View source on GitHub

Find the insertion position (index) of an item in an array with items sorted in ascending order; so that splice(sortedIndex, 0, item) would result in maintaining the array's sort-ness. The array can contain duplicates. If the item already exists in the array the index would be of the first occurrence of the item.

Runs in O(logN) time.

Data First
sortedIndex(data, item);
sortedIndex(["a", "a", "b", "c", "c"], "c"); // => 3
Data Last
sortedIndex(item)(data);
pipe(["a", "a", "b", "c", "c"], sortedIndex("c")); // => 3
sortedIndexBy
GitHub View source on GitHub

Find the insertion position (index) of an item in an array with items sorted in ascending order using a value function; so that splice(sortedIndex, 0, item) would result in maintaining the arrays sort- ness. The array can contain duplicates. If the item already exists in the array the index would be of the first occurrence of the item.

Runs in O(logN) time.

See also:

  • findIndex - scans a possibly unsorted array in-order (linear search).
  • sortedIndex - like this function, but doesn't take a callbackfn.
  • sortedLastIndexBy - like this function, but finds the last suitable index.
  • sortedLastIndex - like sortedIndex, but finds the last suitable index.
  • rankBy - scans a possibly unsorted array in-order, returning the index based on a sorting criteria.
Data First
sortedIndexBy(data, item, valueFunction);
sortedIndexBy([{ age: 20 }, { age: 22 }], { age: 21 }, prop("age")); // => 1
sortedIndexWith
GitHub View source on GitHub

Performs a binary search for the index of the item at which the predicate stops returning true. This function assumes that the array is "sorted" in regards to the predicate, meaning that running the predicate as a mapper on it would result in an array [...true[], ...false[]]. This stricter requirement from the predicate provides us 2 benefits over findIndex which does a similar thing:

  1. It would run at O(logN) time instead of O(N) time.
  2. It always returns a value (it would return data.length if the predicate returns true for all items).

This function is the basis for all other sortedIndex functions which search for a specific item in a sorted array, and it could be used to perform similar efficient searches.

See also:

  • findIndex - scans a possibly unsorted array in-order (linear search).
  • rankBy - scans a possibly unsorted array in-order, returning the index based on a sorting criteria.
Data First
sortedIndexWith(data, predicate);
sortedIndexWith(["a", "ab", "abc"], (item) => item.length < 2); // => 1
Data Last
sortedIndexWith(predicate)(data);
pipe(
  ["a", "ab", "abc"],
  sortedIndexWith((item) => item.length < 2),
); // => 1
sortedLastIndex
GitHub View source on GitHub

Find the insertion position (index) of an item in an array with items sorted in ascending order; so that splice(sortedIndex, 0, item) would result in maintaining the array's sort-ness. The array can contain duplicates. If the item already exists in the array the index would be of the last occurrence of the item.

Runs in O(logN) time.

Data First
sortedLastIndex(data, item);
sortedLastIndex(["a", "a", "b", "c", "c"], "c"); // => 5
Data Last
sortedLastIndex(item)(data);
pipe(["a", "a", "b", "c", "c"], sortedLastIndex("c")); // => 5
sortedLastIndexBy
GitHub View source on GitHub

Find the insertion position (index) of an item in an array with items sorted in ascending order using a value function; so that splice(sortedIndex, 0, item) would result in maintaining the arrays sort- ness. The array can contain duplicates. If the item already exists in the array the index would be of the last occurrence of the item.

Runs in O(logN) time.

See also:

  • findIndex - scans a possibly unsorted array in-order (linear search).
  • sortedLastIndex - a simplified version of this function, without a callbackfn.
  • sortedIndexBy - like this function, but returns the first suitable index.
  • sortedIndex - like sortedLastIndex but without a callbackfn.
  • rankBy - scans a possibly unsorted array in-order, returning the index based on a sorting criteria.
Data First
sortedLastIndexBy(data, item, valueFunction);
sortedLastIndexBy([{ age: 20 }, { age: 22 }], { age: 21 }, prop("age")); // => 1
Data Last
sortedLastIndexBy(item, valueFunction)(data);
pipe([{ age: 20 }, { age: 22 }], sortedLastIndexBy({ age: 21 }, prop("age"))); // => 1

Removes elements from an array and, inserts new elements in their place.

Data First
splice(items, start, deleteCount, replacement);
splice([1, 2, 3, 4, 5, 6, 7, 8], 2, 3, []); //=> [1,2,6,7,8]
splice([1, 2, 3, 4, 5, 6, 7, 8], 2, 3, [9, 10]); //=> [1,2,9,10,6,7,8]
Data Last
splice(start, deleteCount, replacement)(items);
pipe([1, 2, 3, 4, 5, 6, 7, 8], splice(2, 3, [])); // => [1,2,6,7,8]
pipe([1, 2, 3, 4, 5, 6, 7, 8], splice(2, 3, [9, 10])); // => [1,2,9,10,6,7,8]

Splits a given array at a given index.

Data First
splitAt(array, index);
splitAt([1, 2, 3], 1); // => [[1], [2, 3]]
splitAt([1, 2, 3, 4, 5], -1); // => [[1, 2, 3, 4], [5]]
Data Last
splitAt(index)(array);
splitAt(1)([1, 2, 3]); // => [[1], [2, 3]]
splitAt(-1)([1, 2, 3, 4, 5]); // => [[1, 2, 3, 4], [5]]

Splits a given array at the first index where the given predicate returns true.

Data First
splitWhen(array, fn);
splitWhen([1, 2, 3], (x) => x === 2); // => [[1], [2, 3]]
Data Last
splitWhen(fn)(array);
splitWhen((x) => x === 2)([1, 2, 3]); // => [[1], [2, 3]]

Returns the sum of the elements of an array using the provided mapper.

Works for both number and bigint mappers, but not mappers that return both types.

IMPORTANT: The result for empty arrays would be 0 (number) regardless of the type of the mapper; to avoid adding this to the return type for cases where the array is known to be non-empty you can use hasAtLeast or isEmpty to guard against this case.

Data First
sumBy(array, fn);
sumBy([{ a: 5 }, { a: 1 }, { a: 3 }], (x) => x.a); // 9
sumBy([{ a: 5n }, { a: 1n }, { a: 3n }], (x) => x.a); // 9n
Data Last
sumBy(fn)(array);
pipe(
  [{ a: 5 }, { a: 1 }, { a: 3 }],
  sumBy((x) => x.a),
); // 9

pipe(
  [{ a: 5n }, { a: 1n }, { a: 3n }],
  sumBy((x) => x.a),
); // 9n
swapIndices
GitHub View source on GitHub

Swaps the positions of two elements in an array or string at the provided indices.

Negative indices are supported and would be treated as an offset from the end of the array. The resulting type thought would be less strict than when using positive indices.

If either index is out of bounds the result would be a shallow copy of the input, as-is.

Data First
swapIndices(data, index1, index2);
swapIndices(["a", "b", "c"], 0, 1); // => ['b', 'a', 'c']
swapIndices(["a", "b", "c"], 1, -1); // => ['a', 'c', 'b']
swapIndices("abc", 0, 1); // => 'bac'
Data Last
swapIndices(index1, index2)(data);
swapIndices(0, 1)(["a", "b", "c"]); // => ['b', 'a', 'c']
swapIndices(0, -1)("abc"); // => 'cba'

Returns the first n elements of array.

Data First
take(array, n);
take([1, 2, 3, 4, 3, 2, 1], 3); // => [1, 2, 3]
Data Last
take(n)(array);
pipe([1, 2, 3, 4, 3, 2, 1], take(3)); // => [1, 2, 3]
takeFirstBy
GitHub View source on GitHub

Take the first n items from data based on the provided ordering criteria. This allows you to avoid sorting the array before taking the items. The complexity of this function is O(Nlogn) where N is the length of the array.

For the opposite operation (to drop n elements) see dropFirstBy.

Data First
takeFirstBy(data, n, ...rules);
takeFirstBy(["aa", "aaaa", "a", "aaa"], 2, (x) => x.length); // => ['a', 'aa']
Data Last
takeFirstBy(n, ...rules)(data);
pipe(
  ["aa", "aaaa", "a", "aaa"],
  takeFirstBy(2, (x) => x.length),
); // => ['a', 'aa']

Takes the last n elements from the array.

Data First
takeLast(array, n);
takeLast([1, 2, 3, 4, 5], 2); // => [4, 5]
Data Last
takeLast(n)(array);
takeLast(2)([1, 2, 3, 4, 5]); // => [4, 5]
takeLastWhile
GitHub View source on GitHub

Returns elements from the end of the array until the predicate returns false. The returned elements will be in the same order as in the original array.

Data First
takeLastWhile(data, predicate);
takeLastWhile([1, 2, 10, 3, 4, 5], (x) => x < 10); // => [3, 4, 5]
Data Last
takeLastWhile(predicate)(data);
pipe(
  [1, 2, 10, 3, 4, 5],
  takeLastWhile((x) => x < 10),
); // => [3, 4, 5]

Returns elements from the array until predicate returns false.

Data First
takeWhile(data, predicate);
takeWhile([1, 2, 3, 4, 3, 2, 1], (x) => x !== 4); // => [1, 2, 3]
Data Last
takeWhile(predicate)(data);
pipe(
  [1, 2, 3, 4, 3, 2, 1],
  takeWhile((x) => x !== 4),
); // => [1, 2, 3]

Calls an input function n times, returning an array containing the results of those function calls.

fn is passed one argument: The current value of n, which begins at 0 and is gradually incremented to n - 1.

Data First
times(count, fn);
times(5, identity()); //=> [0, 1, 2, 3, 4]
Data Last
times(fn)(count);
times(identity())(5); //=> [0, 1, 2, 3, 4]

Returns a new array containing only one copy of each element in the original list. Elements are compared by reference using Set.

Data First
unique(array);
unique([1, 2, 2, 5, 1, 6, 7]); // => [1, 2, 5, 6, 7]
Data Last
unique()(array);
pipe(
  [1, 2, 2, 5, 1, 6, 7], // only 4 iterations
  unique(),
  take(3),
); // => [1, 2, 5]
uniqueBy
Lazy GitHub View source on GitHub

Returns a new array containing only one copy of each element in the original list transformed by a function. Elements are compared by reference using Set.

Data First
uniqueBy(data, keyFunction);
uniqueBy(
  [{ n: 1 }, { n: 2 }, { n: 2 }, { n: 5 }, { n: 1 }, { n: 6 }, { n: 7 }],
  (obj) => obj.n,
); // => [{n: 1}, {n: 2}, {n: 5}, {n: 6}, {n: 7}]
Data Last
uniqueBy(keyFunction)(data);
pipe(
  [{ n: 1 }, { n: 2 }, { n: 2 }, { n: 5 }, { n: 1 }, { n: 6 }, { n: 7 }], // only 4 iterations
  uniqueBy((obj) => obj.n),
  take(3),
); // => [{n: 1}, {n: 2}, {n: 5}]
uniqueWith
Lazy GitHub View source on GitHub

Returns a new array containing only one copy of each element in the original list. Elements are compared by custom comparator isEquals.

Data First
uniqueWith(array, isEquals);
uniqueWith(
  [{ a: 1 }, { a: 2 }, { a: 2 }, { a: 5 }, { a: 1 }, { a: 6 }, { a: 7 }],
  equals,
); // => [{a: 1}, {a: 2}, {a: 5}, {a: 6}, {a: 7}]
Data Last
uniqueWith(isEquals)(array);
uniqueWith(equals)([
  { a: 1 },
  { a: 2 },
  { a: 2 },
  { a: 5 },
  { a: 1 },
  { a: 6 },
  { a: 7 },
]); // => [{a: 1}, {a: 2}, {a: 5}, {a: 6}, {a: 7}]
pipe(
  [{ a: 1 }, { a: 2 }, { a: 2 }, { a: 5 }, { a: 1 }, { a: 6 }, { a: 7 }], // only 4 iterations
  uniqueWith(equals),
  take(3),
); // => [{a: 1}, {a: 2}, {a: 5}]

Creates a new list from two supplied lists by pairing up equally-positioned items. The length of the returned list will match the shortest of the two inputs.

Data First
zip(first, second);
zip([1, 2], ["a", "b"]); // => [[1, 'a'], [2, 'b']]
Data Last
zip(second)(first);
zip(["a", "b"])([1, 2]); // => [[1, 'a'], [2, 'b']]

Creates a new list from two supplied lists by calling the supplied function with the same-positioned element from each list.

zipWith(fn)(first, second);
zipWith((a: string, b: string) => a + b)(["1", "2", "3"], ["a", "b", "c"]); // => ['1a', '2b', '3c']
Data First
zipWith(first, second, fn);
zipWith(["1", "2", "3"], ["a", "b", "c"], (a, b) => a + b); // => ['1a', '2b', '3c']
Data Last
zipWith(second, fn)(first);
pipe(
  ["1", "2", "3"],
  zipWith(["a", "b", "c"], (a, b) => a + b),
); // => ['1a', '2b', '3c']
conditional
GitHub View source on GitHub

Executes a transformer function based on the first matching predicate, functioning like a series of if...else if... statements. It sequentially evaluates each case and, upon finding a truthy predicate, runs the corresponding transformer, and returns, ignoring any further cases, even if they would match.

NOTE: Some type-predicates may fail to narrow the param type of their transformer; in such cases wrap your type-predicate in an anonymous arrow function: e.g., instead of conditional(..., [myTypePredicate, myTransformer], ...), use conditional(..., [($) => myTypePredicate($), myTransformer], ...).

To add a a default, catch-all, case you can provide a single callback function (instead of a 2-tuple) as the last case. This is equivalent to adding a case with a trivial always-true predicate as it's condition (see example).

For simpler cases you should also consider using when instead.

Due to TypeScript's inability to infer the result of negating a type- predicate we can't refine the types used in subsequent cases based on previous conditions. Using a switch (true) statement or ternary operators is recommended for more precise type control when such type narrowing is needed.

!IMPORTANT! - Unlike similar implementations in Lodash and Ramda, the Remeda implementation doesn't implicitly return undefined as a fallback when when none of the cases match; and instead throws an exception in those cases! You have to explicitly provide a default case, and can use constant(undefined) as your last case to replicate that behavior.

Data First
conditional(data, ...cases);
const nameOrId = 3 as string | number | boolean;

conditional(
  nameOrId,
  [isString, (name) => `Hello ${name}`],
  [isNumber, (id) => `Hello ID: ${id}`],
); //=> 'Hello ID: 3' (typed as `string`), can throw!.

conditional(
  nameOrId,
  [isString, (name) => `Hello ${name}`],
  [isNumber, (id) => `Hello ID: ${id}`],
  constant(undefined),
); //=> 'Hello ID: 3' (typed as `string | undefined`), won't throw.

conditional(
  nameOrId,
  [isString, (name) => `Hello ${name}`],
  [isNumber, (id) => `Hello ID: ${id}`],
  (something) => `Hello something (${JSON.stringify(something)})`,
); //=> 'Hello ID: 3' (typed as `string`), won't throw.
Data Last
conditional(...cases)(data);
const nameOrId = 3 as string | number | boolean;

pipe(
  nameOrId,
  conditional(
    [isString, (name) => `Hello ${name}`],
    [isNumber, (id) => `Hello ID: ${id}`],
  ),
); //=> 'Hello ID: 3' (typed as `string`), can throw!.

pipe(
  nameOrId,
  conditional(
    [isString, (name) => `Hello ${name}`],
    [isNumber, (id) => `Hello ID: ${id}`],
    constant(undefined),
  ),
); //=> 'Hello ID: 3' (typed as `string | undefined`), won't throw.

pipe(
  nameOrId,
  conditional(
    [isString, (name) => `Hello ${name}`],
    [isNumber, (id) => `Hello ID: ${id}`],
    (something) => `Hello something (${JSON.stringify(something)})`,
  ),
); //=> 'Hello ID: 3' (typed as `string`), won't throw.
constant
GitHub View source on GitHub

A function that takes any arguments and returns the provided value on every invocation. This is useful to provide trivial implementations for APIs or in combination with a ternary or other conditional execution to allow to short- circuit more complex implementations for a specific case.

Notice that this is a dataLast impl where the function needs to be invoked to get the "do nothing" function.

See also: doNothing - A function that doesn't return anything. identity - A function that returns the first argument it receives.

Data Last
constant(value);
map([1, 2, 3], constant("a")); // => ['a', 'a', 'a']
map([1, 2, 3], isDemoMode ? add(1) : constant(0)); // => [2, 3, 4] or [0, 0, 0]
debounce
GitHub View source on GitHub

Wraps func with a debouncer object that "debounces" (delays) invocations of the function during a defined cool-down period (waitMs). It can be configured to invoke the function either at the start of the cool-down period, the end of it, or at both ends (timing). It can also be configured to allow invocations during the cool-down period (maxWaitMs). It stores the latest call's arguments so they could be used at the end of the cool-down period when invoking func (if configured to invoke the function at the end of the cool-down period). It stores the value returned by func whenever its invoked. This value is returned on every call, and is accessible via the cachedValue property of the debouncer. Its important to note that the value might be different from the value that would be returned from running func with the current arguments as it is a cached value from a previous invocation. Important: The cool-down period defines the minimum between two invocations, and not the maximum. The period will be extended each time a call is made until a full cool-down period has elapsed without any additional calls.

! DEPRECATED: This implementation of debounce is known to have issues and might not behave as expected. It should be replaced with the funnel utility instead. The test file funnel.remeda-debounce.test.ts offers a reference implementation that replicates debounce via funnel!

Data First
debounce(func, options);
const debouncer = debounce(identity(), { timing: "trailing", waitMs: 1000 });
const result1 = debouncer.call(1); // => undefined
const result2 = debouncer.call(2); // => undefined
// after 1 second
const result3 = debouncer.call(3); // => 2
// after 1 second
debouncer.cachedValue; // => 3
doNothing
GitHub View source on GitHub

A function that takes any arguments and does nothing with them. This is useful as a placeholder for any function or API that requires a void function (a function that doesn't return a value). This could also be used in combination with a ternary or other conditional execution to allow disabling a function call for a specific case.

Notice that this is a dataLast impl where the function needs to be invoked to get the "do nothing" function.

See also:

  • constant - A function that ignores it's arguments and returns the same value on every invocation.
  • identity - A function that returns the first argument it receives.
Data Last
doNothing();
myApi({ onSuccess: handleSuccess, onError: doNothing() });
myApi({ onSuccess: isDemoMode ? doNothing() : handleSuccess });

Creates a funnel that controls the timing and execution of callback. Its main purpose is to manage multiple consecutive (usually fast-paced) calls, reshaping them according to a defined batching strategy and timing policy. This is useful when handling uncontrolled call rates, such as DOM events or network traffic. It can implement strategies like debouncing, throttling, batching, and more.

An optional reducer function can be provided to allow passing data to the callback via calls to call (otherwise the signature of call takes no arguments).

Typing is inferred from callbacks param, and from the rest params that the optional reducer function accepts. Use explicit types for these to ensure that everything else is well-typed.

Notice that this function constructs a funnel object, and does not execute anything when called. The returned object should be used to execute the funnel via the its call method.

  • Debouncing: use minQuietPeriodMs and any triggerAt.
  • Throttling: use minGapMs and triggerAt: "start" or "both".
  • Batching: See the reference implementation in funnel.reference-batch.test.ts.
funnel(callback, options);
const debouncer = funnel(
  () => {
    console.log("Callback executed!");
  },
  { minQuietPeriodMs: 100 },
);
debouncer.call();
debouncer.call();

const throttle = funnel(
  () => {
    console.log("Callback executed!");
  },
  { minGapMs: 100, triggerAt: "start" },
);
throttle.call();
throttle.call();
identity
GitHub View source on GitHub

A function that returns the first argument passed to it.

Notice that this is a dataLast impl where the function needs to be invoked to get the "do nothing" function.

See also:

  • doNothing - A function that doesn't return anything.
  • constant - A function that ignores the input arguments and returns the same value on every invocation.
identity();
map([1, 2, 3], identity()); // => [1,2,3]

Creates a function that is restricted to invoking func once. Repeat calls to the function return the value of the first invocation.

once(fn);
const initialize = once(createApplication);
initialize();
initialize();
// => `createApplication` is invoked once
partialBind
GitHub View source on GitHub

Creates a function that calls func with partial put before the arguments it receives.

Can be thought of as "freezing" some portion of a function's arguments, resulting in a new function with a simplified signature.

Data First
partialBind(func, ...partial);
const fn = (x: number, y: number, z: number) => x * 100 + y * 10 + z;
const partialFn = partialBind(fn, 1, 2);
partialFn(3); //=> 123

const logWithPrefix = partialBind(console.log, "[prefix]");
logWithPrefix("hello"); //=> "[prefix] hello"
partialLastBind
GitHub View source on GitHub

Creates a function that calls func with partial put after the arguments it receives. Note that this doesn't support functions with both optional and rest parameters.

Can be thought of as "freezing" some portion of a function's arguments, resulting in a new function with a simplified signature.

Useful for converting a data-first function to a data-last one.

Data First
partialLastBind(func, ...partial);
const fn = (x: number, y: number, z: number) => x * 100 + y * 10 + z;
const partialFn = partialLastBind(fn, 2, 3);
partialFn(1); //=> 123

const parseBinary = partialLastBind(parseInt, "2");
parseBinary("101"); //=> 5

pipe(
  { a: 1 },
  // instead of (arg) => JSON.stringify(arg, null, 2)
  partialLastBind(JSON.stringify, null, 2),
); //=> '{\n  "a": 1\n}'

Performs left-to-right function composition, passing data through functions in sequence. Each function receives the output of the previous function, creating a readable top-to-bottom data flow that matches how the transformation is executed. This enables converting deeply nested function calls into clear, sequential steps without temporary variables.

When consecutive functions with a lazy tag (e.g., map, filter, take, drop, forEach, etc...) are used together, they process data item-by-item rather than creating intermediate arrays. This enables early termination when only partial results are needed, improving performance for large datasets and expensive operations.

Functions are only evaluated lazily when their data-last form is used directly in the pipe. To disable lazy evaluation, use data-first calls via arrow functions: ($) => map($, callback) instead of map(callback).

Any function can be used in pipes, not just Remeda utilities. For creating custom functions with currying and lazy evaluation support, see the purry utility.

A "headless" variant piped is available for creating reusable pipe functions without initial data.

IMPORTANT: During lazy evaluation, callbacks using the third parameter (the input array) receive only items processed up to that point, not the complete array.

Data First
pipe(data, ...functions);
pipe([1, 2, 3], map(multiply(3))); //=> [3, 6, 9]

// = Early termination with lazy evaluation =
pipe(
  hugeArray,
  map(expensiveComputation),
  filter(complexPredicate),
  // Only processes items until 2 results are found, then stops.
  // Most of hugeArray never gets processed.
  take(2),
);

// = Custom logic within a pipe =
pipe(
  input,
  toLowerCase(),
  normalize,
  ($) => validate($, CONFIG),
  split(","),
  unique(),
);

// = Migrating nested transformations to pipes =
// Nested
const result = prop(
  mapValues(groupByProp(users, "department"), length()),
  "engineering",
);

// Piped
const result = pipe(
  users,
  groupByProp("department"),
  mapValues(length()),
  prop("engineering"),
);

// = Using the 3rd param of a callback =
// The following would print out `data` in its entirety for each value
// of `data`.
forEach([1, 2, 3, 4], (_item, _index, data) => {
  console.log(data);
}); //=> "[1, 2, 3, 4]" logged 4 times

// But with `pipe` data would only contain the items up to the current
// index
pipe(
  [1, 2, 3, 4],
  forEach((_item, _index, data) => {
    console.log(data);
  }),
); //=> "[1]", "[1, 2]", "[1, 2, 3]", "[1, 2, 3, 4]"

Data-last version of pipe. See pipe documentation for full details.

Use piped when you need to pass a transformation as a callback to functions like map and filter, where the data type can be inferred from the call site.

IMPORTANT: piped does not work as a "function factory" in order to create standalone utility functions; because TypeScript cannot infer the input data type (without requiring to explicitly define all type params for all functions in the pipe). We recommend defining the function explicitly, and then use pipe in its implementation.

Data Last
piped(...functions)(data);
map([{ a: 1 }, { a: 2 }, { a: 3 }], piped(prop("a"), add(1))); //=> [2, 3, 4]

Creates a function with dataFirst and dataLast signatures.

purry is a dynamic function and it's not type safe. It should be wrapped by a function that have proper typings. Refer to the example below for correct usage.

!IMPORTANT: functions that simply call purry and return the result (like almost all functions in this library) should return unknown themselves if an explicit return type is required. This is because we currently don't provide a generic return type that is built from the input function, and crafting one manually isn't worthwhile as we rely on function declaration overloading to combine the types for dataFirst and dataLast invocations!

purry(fn, args);
function _findIndex(array, fn) {
  for (let i = 0; i < array.length; i++) {
    if (fn(array[i])) {
      return i;
    }
  }
  return -1;
}

// data-first
function findIndex<T>(array: T[], fn: (item: T) => boolean): number;

// data-last
function findIndex<T>(fn: (item: T) => boolean): (array: T[]) => number;

function findIndex(...args: unknown[]) {
  return purry(_findIndex, args);
}

Conditionally run a function based on a predicate, returning its result (similar to the ?: (ternary) operator.) If the optional onFalse function is not provided, the data will be passed through in those cases.

Supports type predicates to refine the types for both branches and the return value.

Additional arguments are passed to all functions. In data-first calls, they are taken as variadic arguments; but in data-last calls, they are when the curried function itself is called.

For more complex cases check out conditional.

Data First
when(data, predicate, onTrue, ...extraArgs);
when(data, predicate, { onTrue, onFalse }, ...extraArgs);
when(data, isNullish, constant(42));
when(data, (x) => x > 3, { onTrue: add(1), onFalse: multiply(2) });
when(data, isString, (x, radix) => parseInt(x, radix), 10);
Data Last
when(predicate, onTrue)(data, ...extraArgs);
when(predicate, { onTrue, onFalse })(data, ...extraArgs);
pipe(data, when(isNullish, constant(42)));
pipe(
  data,
  when((x) => x > 3, { onTrue: add(1), onFalse: multiply(2) }),
);
map(
  data,
  when(isNullish, (x, index) => x + index),
);
hasSubObject
GitHub View source on GitHub

Checks if subObject is a sub-object of object, which means for every property and value in subObject, there's the same property in object with an equal value. Equality is checked with isDeepEqual.

Data First
hasSubObject(data, subObject);
hasSubObject({ a: 1, b: 2, c: 3 }, { a: 1, c: 3 }); //=> true
hasSubObject({ a: 1, b: 2, c: 3 }, { b: 4 }); //=> false
hasSubObject({ a: 1, b: 2, c: 3 }, {}); //=> true
Data Last
hasSubObject(subObject)(data);
hasSubObject({ a: 1, c: 3 })({ a: 1, b: 2, c: 3 }); //=> true
hasSubObject({ b: 4 })({ a: 1, b: 2, c: 3 }); //=> false
hasSubObject({})({ a: 1, b: 2, c: 3 }); //=> true

A function that checks if the passed parameter is an Array and narrows its type accordingly.

isArray(data);
isArray([5]); //=> true
isArray([]); //=> true
isArray("somethingElse"); //=> false

A function that checks if the passed parameter is a bigint and narrows its type accordingly.

isBigInt(data);
isBigInt(1n); // => true
isBigInt(1); // => false
isBigInt("notANumber"); // => false

A function that checks if the passed parameter is a boolean and narrows its type accordingly.

isBoolean(data);
isBoolean(true); //=> true
isBoolean(false); //=> true
isBoolean("somethingElse"); //=> false

A function that checks if the passed parameter is a Date and narrows its type accordingly.

isDate(data);
isDate(new Date()); //=> true
isDate("somethingElse"); //=> false
isDeepEqual
GitHub View source on GitHub

Performs a deep structural comparison between two values to determine if they are equivalent. For primitive values this is equivalent to ===, for arrays the check would be performed on every item recursively, in order, and for objects all props will be compared recursively.

The built-in Date and RegExp are special-cased and will be compared by their values.

!IMPORTANT: TypedArrays and symbol properties of objects are not supported right now and might result in unexpected behavior. Please open an issue in the Remeda github project if you need support for these types.

The result would be narrowed to the second value so that the function can be used as a type guard.

See:

  • isStrictEqual if you don't need a deep comparison and just want to check for simple (===, Object.is) equality.
  • isShallowEqual if you need to compare arrays and objects "by-value" but don't want to recurse into their values.
Data First
isDeepEqual(data, other);
isDeepEqual(1, 1); //=> true
isDeepEqual(1, "1"); //=> false
isDeepEqual([1, 2, 3], [1, 2, 3]); //=> true
Data Last
isDeepEqual(other)(data);
pipe(1, isDeepEqual(1)); //=> true
pipe(1, isDeepEqual("1")); //=> false
pipe([1, 2, 3], isDeepEqual([1, 2, 3])); //=> true

A function that checks if the passed parameter is defined (!== undefined) and narrows its type accordingly.

isDefined(data);
isDefined("string"); //=> true
isDefined(null); //=> true
isDefined(undefined); //=> false

A function that checks if the passed parameter is empty.

This function has limited utility at the type level because negating it does not yield a useful type in most cases because of TypeScript limitations. Additionally, utilities which accept a narrower input type provide better type-safety on their inputs. In most cases, you should use one of the following functions instead:

  • isEmptyish - supports a wider range of cases, accepts any input including nullish values, and does a better job at narrowing the result.
  • hasAtLeast - when the input is just an array/tuple.
  • isStrictEqual - when you just need to check for a specific literal value.
  • isNullish - when you just care about null and undefined.
  • isTruthy - when you need to also filter number and boolean.
isEmpty(data);
isEmpty(""); //=> true
isEmpty([]); //=> true
isEmpty({}); //=> true

isEmpty("test"); //=> false
isEmpty([1, 2, 3]); //=> false
isEmpty({ a: "hello" }); //=> false

isEmpty(undefined); // Deprecated: use `isEmptyish`

A function that checks if the input is empty. Empty is defined as anything exposing a numerical length, or size property that is equal to 0. This definition covers strings, arrays, Maps, Sets, plain objects, and custom classes. Additionally, null and undefined are also considered empty.

number, bigint, boolean, symbol, and function will always return false. RegExp, Date, and weak collections will always return true. Classes and Errors are treated as plain objects: if they expose any public property they would be considered non-empty, unless they expose a numerical length or size property, which defines their emptiness regardless of other properties.

This function has limited utility at the type level because negating it does not yield a useful type in most cases because of TypeScript limitations. Additionally, utilities which accept a narrower input type provide better type-safety on their inputs. In most cases, you should use one of the following functions instead:

  • isEmpty - provides better type-safety on inputs by accepting a narrower set of cases.
  • hasAtLeast - when the input is just an array/tuple.
  • isStrictEqual - when you just need to check for a specific literal value.
  • isNullish - when you just care about null and undefined.
  • isTruthy - when you need to also filter number and boolean.
isEmptyish(data);
isEmptyish(undefined); //=> true
isEmptyish(null); //=> true
isEmptyish(""); //=> true
isEmptyish([]); //=> true
isEmptyish({}); //=> true
isEmptyish(new Map()); //=> true
isEmptyish(new Set()); //=> true
isEmptyish({ a: "hello", size: 0 }); //=> true
isEmptyish(/abc/); //=> true
isEmptyish(new Date()); //=> true
isEmptyish(new WeakMap()); //=> true

isEmptyish("test"); //=> false
isEmptyish([1, 2, 3]); //=> false
isEmptyish({ a: "hello" }); //=> false
isEmptyish({ length: 1 }); //=> false
isEmptyish(0); //=> false
isEmptyish(true); //=> false
isEmptyish(() => {}); //=> false

A function that checks if the passed parameter is an Error and narrows its type accordingly.

isError(data);
isError(new Error("message")); //=> true
isError("somethingElse"); //=> false

A function that checks if the passed parameter is a Function and narrows its type accordingly.

isFunction(data);
isFunction(() => {}); //=> true
isFunction("somethingElse"); //=> false
isIncludedIn
GitHub View source on GitHub

Checks if the item is included in the container. This is a wrapper around Array.prototype.includes and Set.prototype.has and thus relies on the same equality checks that those functions do (which is reference equality, e.g. ===). In some cases the input's type is also narrowed to the container's item types.

Notice that unlike most functions, this function takes a generic item as it's data and an array as it's parameter.

Data First
isIncludedIn(data, container);
isIncludedIn(2, [1, 2, 3]); // => true
isIncludedIn(4, [1, 2, 3]); // => false

const data = "cat" as "cat" | "dog" | "mouse";
isIncludedIn(data, ["cat", "dog"] as const); // true (typed "cat" | "dog");
Data Last
isIncludedIn(container)(data);
pipe(2, isIncludedIn([1, 2, 3])); // => true
pipe(4, isIncludedIn([1, 2, 3])); // => false

const data = "cat" as "cat" | "dog" | "mouse";
pipe(data, isIncludedIn(["cat", "dog"] as const)); // => true (typed "cat" | "dog");

A function that checks if the passed parameter is not null and narrows its type accordingly. Notice that undefined is not null!

isNonNull(data);
isNonNull("string"); //=> true
isNonNull(null); //=> false
isNonNull(undefined); //=> true
isNonNullish
GitHub View source on GitHub

A function that checks if the passed parameter is defined AND isn't null and narrows its type accordingly.

isNonNullish(data);
isNonNullish("string"); //=> true
isNonNullish(null); //=> false
isNonNullish(undefined); //=> false

A function that takes a guard function as predicate and returns a guard that negates it.

Data Last
isNot(isTruthy)(data);
isNot(isTruthy)(false); //=> true
isNot(isTruthy)(true); //=> false

A function that checks if the passed parameter is either null or undefined and narrows its type accordingly.

isNullish(data);
isNullish(undefined); //=> true
isNullish(null); //=> true
isNullish("somethingElse"); //=> false

A function that checks if the passed parameter is a number and narrows its type accordingly.

isNumber(data);
isNumber(1); // => true
isNumber(1n); // => false
isNumber("notANumber"); // => false
isObjectType
GitHub View source on GitHub

Checks if the given parameter is of type "object" via typeof, excluding null.

It's important to note that in JavaScript, many entities are considered objects, like Arrays, Classes, RegExps, Maps, Sets, Dates, URLs, Promise, Errors, and more. Although technically an object too, null is not considered an object by this function, so that its easier to narrow nullables.

For a more specific check that is limited to plain objects (simple struct/shape/record-like objects), consider using isPlainObject instead. For a simpler check that only removes null from the type prefer isNonNull or isDefined.

Data First
isObjectType(data);
// true
isObjectType({}); //=> true
isObjectType([]); //=> true
isObjectType(Promise.resolve("something")); //=> true
isObjectType(new Date()); //=> true
isObjectType(new Error("error")); //=> true

// false
isObjectType("somethingElse"); //=> false
isObjectType(null); //=> false
isPlainObject
GitHub View source on GitHub

Checks if data is a "plain" object. A plain object is defined as an object with string keys and values of any type, including primitives, other objects, functions, classes, etc (aka struct/shape/record/simple). Technically, a plain object is one whose prototype is either Object.prototype or null, ensuring it does not inherit properties or methods from other object types.

This function is narrower in scope than isObjectType, which accepts any entity considered an "object" by JavaScript's typeof.

Note that Maps, Arrays, and Sets are not considered plain objects and would return false.

isPlainObject(data);
// true
isPlainObject({}); //=> true
isPlainObject({ a: 123 }); //=> true

// false
isPlainObject([]); //=> false
isPlainObject(Promise.resolve("something")); //=> false
isPlainObject(new Date()); //=> false
isPlainObject(new Error("error")); //=> false
isPlainObject("somethingElse"); //=> false
isPlainObject(null); //=> false

A function that checks if the passed parameter is a Promise and narrows its type accordingly.

isPromise(data);
isPromise(Promise.resolve(5)); //=> true
isPromise(Promise.reject(5)); //=> true
isPromise("somethingElse"); //=> false
isShallowEqual
GitHub View source on GitHub

Performs a shallow structural comparison between two values to determine if they are equivalent. For primitive values this is equivalent to ===, for arrays a strict equality check would be performed on every item, in order, and for objects props will be matched and checked for strict equality; Unlike isDeepEqual where the function also recurses into each item and value.

!IMPORTANT: symbol properties of objects are not supported right now and might result in unexpected behavior. Please open an issue in the Remeda github project if you need support for these types.

!IMPORTANT: Promise, Date, and RegExp, are shallowly equal, even when they are semantically different (e.g. resolved promises); but isDeepEqual does compare the latter 2 semantically by-value.

The result would be narrowed to the second value so that the function can be used as a type guard.

See:

  • isStrictEqual if you don't need a deep comparison and just want to check for simple (===, Object.is) equality.
  • isDeepEqual for a recursively deep check of arrays and objects.
Data First
isShallowEqual(data, other);
isShallowEqual(1, 1); //=> true
isShallowEqual(1, "1"); //=> false
isShallowEqual([1, 2, 3], [1, 2, 3]); //=> true
isShallowEqual([[1], [2], [3]], [[1], [2], [3]]); //=> false
Data First
isShallowEqual(other)(data);
pipe(1, isShallowEqual(1)); //=> true
pipe(1, isShallowEqual("1")); //=> false
pipe([1, 2, 3], isShallowEqual([1, 2, 3])); //=> true
pipe([[1], [2], [3]], isShallowEqual([[1], [2], [3]])); //=> false
isStrictEqual
GitHub View source on GitHub

Determines whether two values are functionally identical in all contexts. For primitive values (string, number), this is done by-value, and for objects it is done by-reference (i.e., they point to the same object in memory).

Under the hood we use both the === operator and Object.is. This means that isStrictEqual(NaN, NaN) === true (whereas NaN !== NaN), and isStrictEqual(-0, 0) === true (whereas Object.is(-0, 0) === false).

The result would be narrowed to the second value so that the function can be used as a type guard.

See:

  • isDeepEqual for a semantic comparison that allows comparing arrays and objects "by-value", and recurses for every item.
  • isShallowEqual if you need to compare arrays and objects "by-value" but don't want to recurse into their values.
Data First
isStrictEqual(data, other);
isStrictEqual(1, 1); //=> true
isStrictEqual(1, "1"); //=> false
isStrictEqual([1, 2, 3], [1, 2, 3]); //=> false
Data Last
isStrictEqual(other)(data);
pipe(1, isStrictEqual(1)); //=> true
pipe(1, isStrictEqual("1")); //=> false
pipe([1, 2, 3], isStrictEqual([1, 2, 3])); //=> false

A function that checks if the passed parameter is a string and narrows its type accordingly.

isString(data);
isString("string"); //=> true
isString(1); //=> false

A function that checks if the passed parameter is a symbol and narrows its type accordingly.

isSymbol(data);
isSymbol(Symbol("foo")); //=> true
isSymbol(1); //=> false

A function that checks if the passed parameter is truthy and narrows its type accordingly.

isTruthy(data);
isTruthy("somethingElse"); //=> true
isTruthy(null); //=> false
isTruthy(undefined); //=> false
isTruthy(false); //=> false
isTruthy(0); //=> false
isTruthy(""); //=> false

Adds two numbers.

Data First
add(value, addend);
add(10, 5); // => 15
add(10, -5); // => 5
Data Last
add(addend)(value);
add(5)(10); // => 15
add(-5)(10); // => 5
map([1, 2, 3, 4], add(1)); // => [2, 3, 4, 5]

Rounds up a given number to a specific precision. If you'd like to round up to an integer (i.e. use this function with constant precision === 0), use Math.ceil instead, as it won't incur the additional library overhead.

Data First
ceil(value, precision);
ceil(123.9876, 3); // => 123.988
ceil(483.22243, 1); // => 483.3
ceil(8541, -1); // => 8550
ceil(456789, -3); // => 457000
Data Last
ceil(precision)(value);
ceil(3)(123.9876); // => 123.988
ceil(1)(483.22243); // => 483.3
ceil(-1)(8541); // => 8550
ceil(-3)(456789); // => 457000

Clamp the given value within the inclusive min and max bounds.

Data First
clamp(value, { min, max });
clamp(10, { min: 20 }); // => 20
clamp(10, { max: 5 }); // => 5
clamp(10, { max: 20, min: 5 }); // => 10
Data Last
clamp({ min, max })(value);
clamp({ min: 20 })(10); // => 20
clamp({ max: 5 })(10); // => 5
clamp({ max: 20, min: 5 })(10); // => 10

Divides two numbers.

Data First
divide(value, divisor);
divide(12, 3); // => 4
reduce([1, 2, 3, 4], divide, 24); // => 1
Data Last
divide(divisor)(value);
divide(3)(12); // => 4
map([2, 4, 6, 8], divide(2)); // => [1, 2, 3, 4]

Rounds down a given number to a specific precision. If you'd like to round down to an integer (i.e. use this function with constant precision === 0), use Math.floor instead, as it won't incur the additional library overhead.

Data First
floor(value, precision);
floor(123.9876, 3); // => 123.987
floor(483.22243, 1); // => 483.2
floor(8541, -1); // => 8540
floor(456789, -3); // => 456000
Data Last
floor(precision)(value);
floor(3)(123.9876); // => 123.987
floor(1)(483.22243); // => 483.2
floor(-1)(8541); // => 8540
floor(-3)(456789); // => 456000

Returns the mean of the elements of an array.

Only number arrays are supported, as bigint is unable to represent fractional values.

IMPORTANT: The result for empty arrays would be undefined, regardless of the type of the array. This approach improves type-checking and ensures that cases where NaN might occur are handled properly. To avoid adding this to the return type for cases where the array is known to be non-empty you can use hasAtLeast or isEmpty to guard against this case.

Data First
mean(data);
mean([1, 2, 3]); // => 2
mean([]); // => undefined
Data Last
mean()(data);
pipe([1, 2, 3], mean()); // => 2
pipe([], mean()); // => undefined

Returns the median of the elements of an array.

Only number arrays are supported, as bigint is unable to represent fractional values.

IMPORTANT: The result for empty arrays would be undefined, regardless of the type of the array. This approach improves type-checking and ensures that cases where NaN might occur are handled properly. To avoid adding this to the return type for cases where the array is known to be non-empty you can use hasAtLeast or isEmpty to guard against this case.

Data First
median(data);
pipe([6, 10, 11], median()); // => 10
median([]); // => undefined
Data Last
median()(data);
pipe([6, 10, 11], median()); // => 10
pipe([], median()); // => undefined

Multiplies two numbers.

Data First
multiply(value, multiplicand);
multiply(3, 4); // => 12
reduce([1, 2, 3, 4], multiply, 1); // => 24
Data Last
multiply(multiplicand)(value);
multiply(4)(3); // => 12
map([1, 2, 3, 4], multiply(2)); // => [2, 4, 6, 8]

Compute the product of the numbers in the array, or return 1 for an empty array.

Works for both number and bigint arrays, but not arrays that contain both types.

IMPORTANT: The result for empty arrays would be 1 (number) regardless of the type of the array; to avoid adding this to the return type for cases where the array is known to be non-empty you can use hasAtLeast or isEmpty to guard against this case.

Data First
product(data);
product([1, 2, 3]); // => 6
product([1n, 2n, 3n]); // => 6n
product([]); // => 1
Data Last
product()(data);
pipe([1, 2, 3], product()); // => 6
pipe([1n, 2n, 3n], product()); // => 6n
pipe([], product()); // => 1
randomBigInt
GitHub View source on GitHub

Generate a random bigint between from and to (inclusive).

! Important: In most environments this function uses crypto.getRandomValues() under-the-hood which is cryptographically strong. When the WebCrypto API isn't available (Node 18) we fallback to an implementation that uses Math.random() which is NOT cryptographically secure.

Data First
randomBigInt(from, to);
randomBigInt(1n, 10n); // => 5n
randomInteger
GitHub View source on GitHub

Generate a random integer between from and to (inclusive).

!Important: This function uses Math.random() under-the-hood, which has two major limitations:

  1. It generates 2^52 possible values, so the bigger the range, the less uniform the distribution of values would be, and at ranges larger than that some values would never come up.
  2. It is not cryptographically secure and should not be used for security scenarios.
Data First
randomInteger(from, to);
randomInteger(1, 10); // => 5
randomInteger(1.5, 2.6); // => 2

Rounds a given number to a specific precision. If you'd like to round to an integer (i.e. use this function with constant precision === 0), use Math.round instead, as it won't incur the additional library overhead.

Data First
round(value, precision);
round(123.9876, 3); // => 123.988
round(483.22243, 1); // => 483.2
round(8541, -1); // => 8540
round(456789, -3); // => 457000
Data Last
round(precision)(value);
round(3)(123.9876); // => 123.988
round(1)(483.22243); // => 483.2
round(-1)(8541); // => 8540
round(-3)(456789); // => 457000

Subtracts two numbers.

Data First
subtract(value, subtrahend);
subtract(10, 5); // => 5
subtract(10, -5); // => 15
reduce([1, 2, 3, 4], subtract, 20); // => 10
Data Last
subtract(subtrahend)(value);
subtract(5)(10); // => 5
subtract(-5)(10); // => 15
map([1, 2, 3, 4], subtract(1)); // => [0, 1, 2, 3]

Sums the numbers in the array, or return 0 for an empty array.

Works for both number and bigint arrays, but not arrays that contain both types.

IMPORTANT: The result for empty arrays would be 0 (number) regardless of the type of the array; to avoid adding this to the return type for cases where the array is known to be non-empty you can use hasAtLeast or isEmpty to guard against this case.

Data First
sum(data);
sum([1, 2, 3]); // => 6
sum([1n, 2n, 3n]); // => 6n
sum([]); // => 0
Data Last
sum()(data);
pipe([1, 2, 3], sum()); // => 6
pipe([1n, 2n, 3n], sum()); // => 6n
pipe([], sum()); // => 0

Add a new property to an object.

The function doesn't do any checks on the input object. If the property already exists it will be overwritten, and the type of the new value is not checked against the previous type.

Use set to override values explicitly with better protections.

Data First
addProp(obj, prop, value);
addProp({ firstName: "john" }, "lastName", "doe"); // => {firstName: 'john', lastName: 'doe'}
Data Last
addProp(prop, value)(obj);
addProp("lastName", "doe")({ firstName: "john" }); // => {firstName: 'john', lastName: 'doe'}

Creates a deep copy of the value. Supported types: plain objects, Array, number, string, boolean, Date, and RegExp. Functions are assigned by reference rather than copied. Class instances or any other built-in type that isn't mentioned above are not supported (but might work).

Data First
clone(data);
clone({ foo: "bar" }); // {foo: 'bar'}
Data Last
clone()(data);
pipe({ foo: "bar" }, clone()); // {foo: 'bar'}

Returns an array of key/values of the enumerable properties of an object.

Data First
entries(object);
entries({ a: 1, b: 2, c: 3 }); // => [['a', 1], ['b', 2], ['c', 3]]
Data Last
entries()(object);
pipe({ a: 1, b: 2, c: 3 }, entries()); // => [['a', 1], ['b', 2], ['c', 3]]

Creates a new object by applying functions that is included in evolver object parameter to the data object parameter according to their corresponding path.

Functions included in evolver object will not be invoked if its corresponding key does not exist in the data object. Also, values included in data object will be kept as is if its corresponding key does not exist in the evolver object.

Data First
evolve(data, evolver);
const evolver = {
  count: add(1),
  time: { elapsed: add(1), remaining: add(-1) },
};
const data = {
  id: 10,
  count: 10,
  time: { elapsed: 100, remaining: 1400 },
};
evolve(data, evolver);
// => {
//   id: 10,
//   count: 11,
//   time: { elapsed: 101, remaining: 1399 },
// }
Data Last
evolve(evolver)(data);
const evolver = {
  count: add(1),
  time: { elapsed: add(1), remaining: add(-1) },
};
const data = {
  id: 10,
  count: 10,
  time: { elapsed: 100, remaining: 1400 },
};
pipe(data, evolve(evolver));
// => {
//   id: 10,
//   count: 11,
//   time: { elapsed: 101, remaining: 1399 },
// }
forEachObj
GitHub View source on GitHub

Iterate an object using a defined callback function.

The dataLast version returns the original object (instead of not returning anything (void)) to allow using it in a pipe. The returned object is the same reference as the input object, and not a shallow copy of it!

Data First
forEachObj(object, fn);
forEachObj({ a: 1 }, (val, key, obj) => {
  console.log(`${key}: ${val}`);
}); // "a: 1"
Data Last
forEachObj(fn)(object);
pipe(
  { a: 1 },
  forEachObj((val, key) => console.log(`${key}: ${val}`)),
); // "a: 1"
fromEntries
GitHub View source on GitHub

Creates a new object from an array of tuples by pairing up first and second elements as {[key]: value}. If a tuple is not supplied for any element in the array, the element will be ignored If duplicate keys exist, the tuple with the greatest index in the input array will be preferred.

The strict option supports more sophisticated use-cases like those that would result when calling the strict toPairs function.

There are several other functions that could be used to build an object from an array:

  • fromKeys - Builds an object from an array of keys and a mapper for values.
  • indexBy - Builds an object from an array of values and a mapper for keys.
  • pullObject - Builds an object from an array of items with mappers for both keys and values. Refer to the docs for more details.
Data First
fromEntries(tuples);
fromEntries([
  ["a", "b"],
  ["c", "d"],
]); // => {a: 'b', c: 'd'}
Data Last
fromEntries()(tuples);
pipe(
  [
    ["a", "b"],
    ["c", "d"],
  ] as const,
  fromEntries(),
); // => {a: 'b', c: 'd'}

Creates an object that maps each key in data to the result of mapper for that key. Duplicate keys are overwritten, guaranteeing that mapper is run for each item in data.

There are several other functions that could be used to build an object from an array:

  • indexBy - Builds an object from an array of values and a mapper for keys.
  • pullObject - Builds an object from an array of items with mappers for both keys and values.
  • fromEntries - Builds an object from an array of key-value pairs. Refer to the docs for more details.
Data First
fromKeys(data, mapper);
fromKeys(["cat", "dog"], length()); // { cat: 3, dog: 3 } (typed as Partial<Record<"cat" | "dog", number>>)
fromKeys([1, 2], add(1)); // { 1: 2, 2: 3 } (typed as Partial<Record<1 | 2, number>>)
Data Last
fromKeys(mapper)(data);
pipe(["cat", "dog"], fromKeys(length())); // { cat: 3, dog: 3 } (typed as Partial<Record<"cat" | "dog", number>>)
pipe([1, 2], fromKeys(add(1))); // { 1: 2, 2: 3 } (typed as Partial<Record<1 | 2, number>>)

Returns an object whose keys and values are swapped. If the object contains duplicate values, subsequent values will overwrite previous values.

Data First
invert(object);
invert({ a: "d", b: "e", c: "f" }); // => { d: "a", e: "b", f: "c" }
Data Last
invert()(object);
pipe({ a: "d", b: "e", c: "f" }, invert()); // => { d: "a", e: "b", f: "c" }

Returns a new array containing the keys of the array or object.

Data First
keys(source);
keys(["x", "y", "z"]); // => ['0', '1', '2']
keys({ a: "x", b: "y", 5: "z" }); // => ['a', 'b', '5']
Data Last
keys()(source);
pipe(["x", "y", "z"], keys()); // => ['0', '1', '2']
pipe({ a: "x", b: "y", 5: "z" } as const, keys()); // => ['a', 'b', '5']

Maps keys of object and keeps the same values.

Data First
mapKeys(object, fn);
mapKeys({ a: 1, b: 2 }, (key, value) => key + value); // => { a1: 1, b2: 2 }
Data Last
mapKeys(fn)(object);
pipe(
  { a: 1, b: 2 },
  mapKeys((key, value) => key + value),
); // => { a1: 1, b2: 2 }

Maps values of object and keeps the same keys. Symbol keys are not passed to the mapper and will be removed from the output object.

To also copy the symbol keys to the output use merge: merge(data, mapValues(data, mapper))).

Data First
mapValues(data, mapper);
mapValues({ a: 1, b: 2 }, (value, key) => value + key); // => {a: '1a', b: '2b'}
Data Last
mapValues(mapper)(data);
pipe(
  { a: 1, b: 2 },
  mapValues((value, key) => value + key),
); // => {a: '1a', b: '2b'}

Merges two objects into one by combining their properties, effectively creating a new object that incorporates elements from both. The merge operation prioritizes the second object's properties, allowing them to overwrite those from the first object with the same names.

Equivalent to { ...data, ...source }.

Data First
merge(data, source);
merge({ x: 1, y: 2 }, { y: 10, z: 2 }); // => { x: 1, y: 10, z: 2 }
Data Last
merge(source)(data);
pipe({ x: 1, y: 2 }, merge({ y: 10, z: 2 })); // => { x: 1, y: 10, z: 2 }

Merges the source object into the destination object. The merge is similar to performing { ...destination, ... source } (where disjoint values from each object would be copied as-is, and for any overlapping props the value from source would be used); But for each prop (p), if both destination and source have a plain-object as a value, the value would be taken as the result of recursively deepMerging them (result.p === deepMerge(destination.p, source.p)).

Data First
mergeDeep(destination, source);
mergeDeep({ foo: "bar", x: 1 }, { foo: "baz", y: 2 }); // => { foo: 'baz', x: 1, y: 2 }
Data Last
mergeDeep(source)(destination);
pipe({ foo: "bar", x: 1 }, mergeDeep({ foo: "baz", y: 2 })); // => { foo: 'baz', x: 1, y: 2 }

Creates an object containing a single key:value pair.

objOf(value, key);
objOf(10, "a"); // => { a: 10 }
objOf(key)(value);
pipe(10, objOf("a")); // => { a: 10 }

Returns a partial copy of an object omitting the keys specified.

Data First
omit(obj, keys);
omit({ a: 1, b: 2, c: 3, d: 4 }, ["a", "d"]); // => { b: 2, c: 3 }
Data Last
omit(keys)(obj);
pipe({ a: 1, b: 2, c: 3, d: 4 }, omit(["a", "d"])); // => { b: 2, c: 3 }

Creates a shallow copy of the data, and then removes any keys that the predicate rejects. Symbol keys are not passed to the predicate and would be passed through to the output as-is.

See pickBy for a complementary function which starts with an empty object and adds the entries that the predicate accepts. Because it is additive, symbol keys will not be passed through to the output object.

Data First
omitBy(data, predicate);
omitBy({ a: 1, b: 2, A: 3, B: 4 }, (val, key) => key.toUpperCase() === key); // => {a: 1, b: 2}
Data Last
omitBy(fn)(object);
omitBy((val, key) => key.toUpperCase() === key)({ a: 1, b: 2, A: 3, B: 4 }); // => {a: 1, b: 2}

Gets the value at path of object. If the resolved value is null or undefined, the defaultValue is returned in its place.

DEPRECATED: Use defaultTo(prop(object, ...path), defaultValue) instead!

Data First
pathOr(object, array, defaultValue);
pathOr({ x: 10 }, ["y"], 2); // 2
pathOr({ y: 10 }, ["y"], 2); // 10
Data Last
pathOr(array, defaultValue)(object);
pipe({ x: 10 }, pathOr(["y"], 2)); // 2
pipe({ y: 10 }, pathOr(["y"], 2)); // 10

Creates an object composed of the picked data properties.

Data First
pick(object, [prop1, prop2]);
pick({ a: 1, b: 2, c: 3, d: 4 }, ["a", "d"]); // => { a: 1, d: 4 }
Data Last
pick([prop1, prop2])(object);
pipe({ a: 1, b: 2, c: 3, d: 4 }, pick(["a", "d"])); // => { a: 1, d: 4 }

Iterates over the entries of data and reconstructs the object using only entries that predicate accepts. Symbol keys are not passed to the predicate and would be filtered out from the output object.

See omitBy for a complementary function which starts with a shallow copy of the input object and removes the entries that the predicate rejects. Because it is subtractive symbol keys would be copied over to the output object. See also entries, filter, and fromEntries which could be used to build your own version of pickBy if you need more control (though the resulting type might be less precise).

Data First
pickBy(data, predicate);
pickBy({ a: 1, b: 2, A: 3, B: 4 }, (val, key) => key.toUpperCase() === key); // => {A: 3, B: 4}
Data Last
pickBy(predicate)(data);
pipe(
  { a: 1, b: 2, A: 3, B: 4 },
  pickBy((val, key) => key.toUpperCase() === key),
); // => {A: 3, B: 4}

Gets the value of the given property from an object. Nested properties can be accessed by providing a variadic array of keys that define the path from the root to the desired property. Arrays can be accessed by using numeric keys. Unions and optional properties are handled gracefully by returning undefined early for any non-existing property on the path. Paths are validated against the object type to provide stronger type safety, better compile-time errors, and to enable autocompletion in IDEs.

Data First
prop(data, ...keys);
prop({ foo: { bar: "baz" } }, "foo"); //=> { bar: 'baz' }
prop({ foo: { bar: "baz" } }, "foo", "bar"); //=> 'baz'
prop(["cat", "dog"], 1); //=> 'dog'
Data Last
prop(...keys)(data);
pipe({ foo: { bar: "baz" } }, prop("foo")); //=> { bar: 'baz' }
pipe({ foo: { bar: "baz" } }, prop("foo", "bar")); //=> 'baz'
pipe(["cat", "dog"], prop(1)); //=> 'dog'
pullObject
GitHub View source on GitHub

Creates an object that maps the result of valueExtractor with a key resulting from running keyExtractor on each item in data. Duplicate keys are overwritten, guaranteeing that the extractor functions are run on each item in data.

There are several other functions that could be used to build an object from an array:

  • fromKeys - Builds an object from an array of keys and a mapper for values.
  • indexBy - Builds an object from an array of values and a mapper for keys.
  • fromEntries - Builds an object from an array of key-value pairs. Refer to the docs for more details.
Data First
pullObject(data, keyExtractor, valueExtractor);
pullObject(
  [
    { name: "john", email: "john@remedajs.com" },
    { name: "jane", email: "jane@remedajs.com" },
  ],
  prop("name"),
  prop("email"),
); // => { john: "john@remedajs.com", jane: "jane@remedajs.com" }
Data Last
pullObject(keyExtractor, valueExtractor)(data);
pipe(
  [
    { name: "john", email: "john@remedajs.com" },
    { name: "jane", email: "jane@remedajs.com" },
  ],
  pullObject(prop("name"), prop("email")),
); // => { john: "john@remedajs.com", jane: "jane@remedajs.com" }

Sets the value at prop of object.

To add a new property to an object, or to override its type, use addProp instead, and to set a property within a nested object use setPath.

Data First
set(obj, prop, value);
set({ a: 1 }, "a", 2); // => { a: 2 }
Data Last
set(prop, value)(obj);
pipe({ a: 1 }, set("a", 2)); // => { a: 2 }

Sets the value at path of object.

For simple cases where the path is only one level deep, prefer set instead.

Data First
setPath(obj, path, value);
setPath({ a: { b: 1 } }, ["a", "b"], 2); // => { a: { b: 2 } }
Data Last
setPath(path, value)(obj);
pipe({ a: { b: 1 } }, setPath(["a", "b"], 2)); // { a: { b: 2 } }

Swaps the values of two properties in an object based on the provided keys.

Data First
swapProps(data, key1, key2);
swapProps({ a: 1, b: 2, c: 3 }, "a", "b"); // => {a: 2, b: 1, c: 3}
Data Last
swapProps(key1, key2)(data);
swapProps("a", "b")({ a: 1, b: 2, c: 3 }); // => {a: 2, b: 1, c: 3}

Returns a new array containing the values of the array or object.

Data First
values(source);
values(["x", "y", "z"]); // => ['x', 'y', 'z']
values({ a: "x", b: "y", c: "z" }); // => ['x', 'y', 'z']
Data Last
values()(source);
pipe(["x", "y", "z"], values()); // => ['x', 'y', 'z']
pipe({ a: "x", b: "y", c: "z" }, values()); // => ['x', 'y', 'z']
pipe({ a: "x", b: "y", c: "z" }, values(), first()); // => 'x'

A stricter wrapper around the Nullish coalescing operator ?? that ensures that the fallback matches the type of the data. Only works when data can be null or undefined.

Notice that Number.NaN is not nullish and would not result in returning the fallback!

Data First
defaultTo(data, fallback);
defaultTo("hello" as string | undefined, "world"); //=> "hello"
defaultTo(undefined as string | undefined, "world"); //=> "world"
Data Last
defaultTo(fallback)(data);
pipe("hello" as string | undefined, defaultTo("world")); //=> "hello"
pipe(undefined as string | undefined, defaultTo("world")); //=> "world"

Calls the given function with the given value, then returns the given value. The return value of the provided function is ignored.

This allows "tapping into" a function sequence in a pipe, to perform side effects on intermediate results.

Data First
tap(value, fn);
tap("foo", console.log); // => "foo"
Data Last
tap(fn)(value);
pipe(
  [-5, -1, 2, 3],
  filter((n) => n > 0),
  tap(console.log), // prints [2, 3]
  map((n) => n * 2),
); // => [4, 6]
capitalize
GitHub View source on GitHub

Makes the first character of a string uppercase while leaving the rest unchanged.

It uses the built-in String.prototype.toUpperCase for the runtime and the built-in Capitalize utility type for typing and thus shares their locale inaccuracies.

For display purposes, prefer using the CSS pseudo-element ::first-letter to target just the first letter of the word, and text-transform: uppercase to capitalize it. This transformation is locale-aware.

For other case manipulations see: toUpperCase, toLowerCase, uncapitalize, toCamelCase, toKebabCase, toSnakeCase, and toTitleCase.

Data First
capitalize(data);
capitalize("hello world"); // "Hello world"
Data Last
capitalize()(data);
pipe("hello world", capitalize()); // "Hello world"

Determines whether a string ends with the provided suffix, and refines the output type if possible.

This function is a wrapper around the built-in String.prototype.endsWith method, but doesn't expose the endPosition parameter. To check only up to a specific position, use endsWith(sliceString(data, 0, endPosition), suffix).

Data First
endsWith(data, suffix);
endsWith("hello world", "hello"); // false
endsWith("hello world", "world"); // true
Data Last
endsWith(suffix)(data);
pipe("hello world", endsWith("hello")); // false
pipe("hello world", endsWith("world")); // true
Data First
randomString(length);
randomString(5); // => aB92J
Data Last
randomString()(length);
pipe(5, randomString()); // => aB92J
sliceString
GitHub View source on GitHub

Extracts a section of a string between two indices.

This function is a wrapper around the built-in String.prototype.slice method.

Data First
sliceString(data, indexStart, indexEnd);
sliceString("abcdefghijkl", 1); // => `bcdefghijkl`
sliceString("abcdefghijkl", 4, 7); // => `efg`
Data Last
sliceString(indexStart, indexEnd)(string);
sliceString(1)("abcdefghijkl"); // => `bcdefghijkl`
sliceString(4, 7)("abcdefghijkl"); // => `efg`

Splits a string into an array of substrings using a separator pattern.

This function is a wrapper around the built-in String.prototype.split method.

Data First
split(data, separator, limit);
split("a,b,c", ","); //=> ["a", "b", "c"]
split("a,b,c", ",", 2); //=> ["a", "b"]
split("a1b2c3d", /\d/u); //=> ["a", "b", "c", "d"]
Data Last
split(separator, limit)(data);
pipe("a,b,c", split(",")); //=> ["a", "b", "c"]
pipe("a,b,c", split(",", 2)); //=> ["a", "b"]
pipe("a1b2c3d", split(/\d/u)); //=> ["a", "b", "c", "d"]
startsWith
GitHub View source on GitHub

Determines whether a string begins with the provided prefix, and refines the output type if possible.

This function is a wrapper around the built-in String.prototype.startsWith method, but doesn't expose the startPosition parameter. To check from a specific position, use startsWith(sliceString(data, startPosition), prefix).

Data First
startsWith(data, prefix);
startsWith("hello world", "hello"); // true
startsWith("hello world", "world"); // false
Data Last
startsWith(prefix)(data);
pipe("hello world", startsWith("hello")); // true
pipe("hello world", startsWith("world")); // false
toCamelCase
GitHub View source on GitHub

Converts text to camelCase by splitting it into words, lowercasing the first word, capitalizing the rest, then joining them back together.

Because it uses the built-in case conversion methods, the function shares their locale inaccuracies too, making it best suited for simple strings like identifiers and internal keys. For linguistic text processing, use Intl.Segmenter with granularity: "word", toLocaleLowerCase, and toLocaleUpperCase which are purpose-built to handle nuances in languages and locales.

For other case manipulations see: toLowerCase, toUpperCase, capitalize, uncapitalize, toKebabCase, toSnakeCase, and toTitleCase.

For PascalCase use capitalize(toCamelCase(data)).

Data First
toCamelCase(data);
toCamelCase(data, { preserveConsecutiveUppercase });
toCamelCase("hello world"); // "helloWorld"
toCamelCase("__HELLO_WORLD__"); // "helloWorld"
toCamelCase("HasHTML"); // "hasHTML"
toCamelCase("HasHTML", { preserveConsecutiveUppercase: false }); // "hasHtml"
Data Last
toCamelCase()(data);
toCamelCase({ preserveConsecutiveUppercase })(data);
pipe("hello world", toCamelCase()); // "helloWorld"
pipe("__HELLO_WORLD__", toCamelCase()); // "helloWorld"
pipe("HasHTML", toCamelCase()); // "hasHTML"
pipe("HasHTML", toCamelCase({ preserveConsecutiveUppercase: false })); // "hasHtml"
toKebabCase
GitHub View source on GitHub

Converts text to kebab-case by splitting it into words and joining them back together with hyphens (-), then lowercasing the result.

Because it uses toLowerCase, the function shares its locale inaccuracies too, making it best suited for simple strings like identifiers and internal keys. For linguistic text processing, use Intl.Segmenter with granularity: "word", and toLocaleLowerCase, which are purpose-built to handle nuances in languages and locales.

For other case manipulations see: toLowerCase, toUpperCase, capitalize, uncapitalize, toCamelCase, toSnakeCase, and toTitleCase.

For COBOL-CASE use toUpperCase(toKebabCase(data)).

Data First
toKebabCase(data);
toKebabCase("hello world"); // "hello-world"
toKebabCase("__HELLO_WORLD__"); // "hello-world"
Data Last
toKebabCase()(data);
pipe("hello world", toKebabCase()); // "hello-world"
pipe("__HELLO_WORLD__", toKebabCase()); // "hello-world"
toLowerCase
GitHub View source on GitHub
Data First
toLowerCase(data);
toLowerCase("Hello World"); // "hello world"
Data Last
toLowerCase()(data);
pipe("Hello World", toLowerCase()); // "hello world"
toSnakeCase
GitHub View source on GitHub

Converts text to snake_case by splitting it into words and joining them back together with underscores (_), then lowercasing the result.

Because it uses toLowerCase, the function shares its locale inaccuracies too, making it best suited for simple strings like identifiers and internal keys. For linguistic text processing, use Intl.Segmenter with granularity: "word", and toLocaleLowerCase, which are purpose-built to handle nuances in languages and locales.

For other case manipulations see: toLowerCase, toUpperCase, capitalize, uncapitalize, toCamelCase, toKebabCase, and toTitleCase.

For CONSTANT_CASE use toUpperCase(toSnakeCase(data)).

Data First
toSnakeCase(data);
toSnakeCase("hello world"); // "hello_world"
toSnakeCase("__HELLO_WORLD__"); // "hello_world"
Data Last
toSnakeCase()(data);
pipe("hello world", toSnakeCase()); // "hello_world"
pipe("__HELLO_WORLD__", toSnakeCase()); // "hello_world"
toTitleCase
GitHub View source on GitHub

Converts text to Title Case by splitting it into words, capitalizing the first letter of each word, then joining them back together with spaces.

Because it uses the built-in case conversion methods, the function shares their locale inaccuracies, making it best suited for simple strings like identifiers and internal keys. For linguistic text processing, use Intl.Segmenter with granularity: "word", toLocaleLowerCase, and toLocaleUpperCase which are purpose-built to handle nuances in languages and locales.

For other case manipulations see: toLowerCase, toUpperCase, capitalize, uncapitalize, toCamelCase, toKebabCase, and toSnakeCase.

Data First
toTitleCase(data);
toTitleCase(data, { preserveConsecutiveUppercase });
toTitleCase("hello world"); // "Hello World"
toTitleCase("--foo-bar--"); // "Foo Bar"
toTitleCase("fooBar"); // "Foo Bar"
toTitleCase("__FOO_BAR__"); // "Foo Bar"
toTitleCase("XMLHttpRequest"); // "XML Http Request"
toTitleCase("XMLHttpRequest", { preserveConsecutiveUppercase: false }); // "Xml Http Request"
Data Last
toTitleCase()(data);
toTitleCase({ preserveConsecutiveUppercase })(data);
pipe("hello world", toTitleCase()); // "Hello World"
pipe("--foo-bar--", toTitleCase()); // "Foo Bar"
pipe("fooBar", toTitleCase()); // "Foo Bar"
pipe("__FOO_BAR__", toTitleCase()); // "Foo Bar"
pipe("XMLHttpRequest", toTitleCase()); // "XML Http Request"
pipe("XMLHttpRequest", toTitleCase({ preserveConsecutiveUppercase: false })); // "Xml Http Request"
toUpperCase
GitHub View source on GitHub
Data First
toUpperCase(data);
toUpperCase("Hello World"); // "HELLO WORLD"
Data Last
toUpperCase()(data);
pipe("Hello World", toUpperCase()); // "HELLO WORLD"

Truncates strings to a maximum length, adding an ellipsis when truncated.

Shorter strings are returned unchanged. If the omission marker is longer than the maximum length, it will be truncated as well.

The separator argument provides more control by optimistically searching for a matching cutoff point, which could be used to avoid truncating in the middle of a word or other semantic boundary.

If you just need to limit the total length of the string, without adding an omission or optimizing the cutoff point via separator, prefer sliceString instead, which runs more efficiently.

The function counts Unicode characters, not visual graphemes, and may split emojis, denormalized diacritics, or combining characters, in the middle. For display purposes, prefer CSS text-overflow: ellipsis which is locale-aware and purpose-built for this task.

Data First
truncate(data, n, { omission, separator });
truncate("Hello, world!", 8); //=> "Hello..."
truncate("cat, dog, mouse", 12, { omission: "__", separator: "," }); //=> "cat, dog__"
Data Last
truncate(n, { omission, separator })(data);
pipe("Hello, world!" as const, truncate(8)); //=> "Hello..."
pipe(
  "cat, dog, mouse" as const,
  truncate(12, { omission: "__", separator: "," }),
); //=> "cat, dog__"
uncapitalize
GitHub View source on GitHub

Makes the first character of a string lowercase while leaving the rest unchanged.

It uses the built-in String.prototype.toLowerCase for the runtime and the built-in Uncapitalize utility type for typing and thus shares their locale inaccuracies.

For display purposes, prefer using the CSS pseudo-element ::first-letter to target just the first letter of the word, and text-transform: lowercase to lowercase it. This transformation is locale-aware.

For other case manipulations see: toUpperCase, toLowerCase, capitalize, toCamelCase, toKebabCase, toSnakeCase, and toTitleCase.

Data First
uncapitalize(data);
uncapitalize("HELLO WORLD"); // "hELLO WORLD"
Data Last
uncapitalize()(data);
pipe("HELLO WORLD", uncapitalize()); // "hELLO WORLD"
stringToPath
GitHub View source on GitHub

A utility to allow JSONPath-like strings to be used in other utilities which take an array of path segments as input (e.g. prop, setPath, etc...). The main purpose of this utility is to act as a bridge between the runtime implementation that converts the path to an array, and the type-system that parses the path string type into an array type. This type allows us to return fine-grained types and to enforce correctness at the type-level.

We discourage using this utility for new code. This utility is for legacy code that already contains path strings (which are accepted by Lodash). We strongly recommend using path arrays instead as they provide better developer experience via significantly faster type-checking, fine-grained error messages, and automatic typeahead suggestions for each segment of the path.

There are a bunch of limitations to this utility derived from the limitations of the type itself, these are usually edge-cases around deeply nested paths, escaping, whitespaces, and empty segments. This is true even in cases where the runtime implementation can better handle them, this is intentional. See the tests for this utility for more details and the expected outputs.

Data First
stringToPath(path);
stringToPath("a.b[0].c"); // => ['a', 'b', 0, 'c']