Skip to main content

Migrate: ramda

Function

addIndex

Not provided by Remeda.

You don’t need addIndex In Remeda because all functions that iterate over arrays or objects have their callbacks in the format that addIndex returns by default. If you still have a use-case that isn’t possible via Remeda please open an issue at the Remeda GitHub project.

// Ramda
addIndex(map)((val, idx) => idx + "-" + val, DATA);

// Remeda
map(DATA, (val, idx) => idx + "-" + val);

F

constant

Use constant with the constant false. Notice that in Ramda you use F itself as the function, but in Remeda constant is a factory that creates the replacement function.

// Ramda
F;

// Remeda
constant(false);

identity

identity

In Remeda the identity function is a factory that creates an identity function; it needs to be called to be used.

// Ramda
map(identity);

// Remeda
map(identity());

partial

partialBind

Remeda’s partialBind takes a variadic list of arguments instead of an array.

function greet(greeting, firstName, lastName) {
  return greeting + " " + firstName + " " + lastName;
}

// Ramda
partial(greet, ["hi", "john"]);

// Remeda
partialBind(greet, "hi", "john");

partialRight

partialLastBind

Remeda’s partialLastBind takes a variadic list of arguments instead of an array.

function greet(greeting, firstName, lastName) {
  return greeting + " " + firstName + " " + lastName;
}

// Ramda
partialRight(greet, ["john", "doe"]);

// Remeda
partialLastBind(greet, "john", "doe");

T

constant

Use constant with the constant true. Notice that in Ramda you use T itself as the function, but in Remeda constant is a factory that creates the replacement function.

// Ramda
T;

// Remeda
constant(true);

List

append

concat

Not provided by Remeda.

  • You can replicate this function via the native JS spread ... operator or via the Remeda concat function (by wrapping the operand with an array).
  • There might be cases where building an append function could be more efficient than using the suggested alternatives, but we believe they are extremely rare. If you want to suggest adding it reach out to us at the Remeda GitHub project.
// Ramda
append(operand, DATA);

// Or curried
const addsAbc = append(operand);

// Remeda
concat(DATA, [operand]);

// Or in a pipe
pipe(DATA, concat([operand]));

// Native
[...DATA, operand];

const addsAbc = <T extends readonly unknown[]>(data: T) => [...data, operand];

flatten

flat

Unlike flatten in Ramda, the Remeda flat function is always bound by the depth param. To replicate the Ramda behavior use a high, const value. Infinity and Number.MAX_INTEGER are not consts and would result in inefficient typing.

// Ramda
flatten(DATA);

// Remeda
flat(DATA, 100); // ✅
flat(DATA, Infinity); // ❌

includes

isIncludedIn

Arrays

// Ramda
includes(1, [1, 2, 3]);

// Remeda
isIncludedIn(1, [1, 2, 3]);

Strings

const DATA = "Hello, World!";

// Remeda
includes("lo", DATA);

// Native
DATA.includes("lo");

Object items

const DATA = [{ name: "Fred" }];

// Ramda
includes({ name: "Fred" }, DATA);

// Remeda
DATA.some(isDeepEqual({ name: "Fred" }));

Array items

const DATA = [[42]];

// Ramda
includes([42], DATA);

// Remeda
DATA.some(isDeepEqual([42]));

init

dropLast
  • Equivalent to dropLast with an argument of 1.
  • On strings use sliceString with 0 and -1 as arguments instead.

Arrays

// Ramda
init([1, 2, 3]);

// Remeda
dropLast([1, 2, 3], 1);

Strings

// Ramda
init("abc");

// Remeda
sliceString("abc", 0, -1);

last

last

For strings use sliceString with -1 as an argument instead.

Arrays

// Ramda
last([1, 2, 3]);

// Remeda
last([1, 2, 3]);

Strings

// Ramda
last("abc");

// Remeda
sliceString("abc", -1);

mapAccum

mapWithFeedback

Remeda’s mapWithFeedback has some differences from Ramda’s mapAccum, but could be used to achieve the same results:

  • The mapper function only returns a single value for both the accumulator and the value (like reduce does). mapWithFeedback would not work if you need these to have different values.
  • Only the accumulated array is returned instead of a tuple. The final result of the computation would always be the last element in this list, and could be retrieved using last.
// Ramda
const result = mapAccum((a, b) => [a + b, a + b], 0, ["1", "2", "3", "4"]);

// Remeda
const temp = mapWithFeedback(["1", "2", "3", "4"], (a, b) => a + b, 0);
const result = [last(temp), temp];

nth

Not provided by Remeda.

  • For index 0 use first.
  • For index -1 use last.
  • For arbitrary non-negative indices use the native JS data[n].
  • Or use Array.prototype.at for any index.
// Ramda
nth(0, DATA);

// Remeda
first(DATA);

// Ramda
nth(1, DATA);

// Native
DATA[1];
DATA.at(1);

// Ramda
nth(-1, DATA);

// Remeda
last(DATA);

// Ramda
nth(-2, DATA);

// Native
DATA.at(-2);

pluck

map

Not provided by Remeda.

  • pluck(data, k) is equivalent to map(data, prop(k)).

  • When data is an object (and not an array) use mapValues instead.

Arrays

const DATA = [{ val: "hello" }, { val: "world" }];

// Ramda
R.pluck("val", DATA); //=> ["hello", "world"];

// Remeda
map(DATA, prop("val"));

Objects

const DATA = { a: { val: "hello" }, b: { val: "world" } };

// Ramda
R.pluck("val", DATA); //=> { a: "hello", b: "world" };

// Remeda
mapValues(DATA, prop("val"));

range

range

Remeda curries functions by stripping the first parameter. This means that unlike in Ramda, a curried call to range would result in a function that has a pre-set end value, and not a pre-set start value; curried calls need their start and end parameters swapped!

Simple

// Ramda
R.range(10, 20);
R.range(start, end);

// Remeda
range(10, 20);
range(start, end);

Curried

// Ramda
R.range(10)(20);
R.range(start)(end);

// Remeda
range(20)(10);
range(end)(start);

reject

filter

Wrap the callback with isNot.

// Ramda
reject(predicate, DATA);

// Remeda
filter(DATA, isNot(predicate));

// Or in a pipe
pipe(DATA, filter(isNot(predicate)));

tail

drop
  • Equivalent to drop with an argument of 1.
  • On strings use sliceString instead.

Arrays

// Ramda
tail([1, 2, 3]);

// Remeda
drop([1, 2, 3], 1);

Strings

// Ramda
tail("abc");

// Remeda
sliceString("abc", 1);

zipObj

Not provided by Remeda.

Compose zip and fromEntries:

// Ramda
zipObj(keys, values);

// Remeda
fromEntries(zip(keys, values));

Logic

defaultTo

defaultTo
  • Number.NaN is not considered nullish and would not result in returning the default value. Use when with the built-in Number.isNaN and a constant for the fallback value.
  • Unlike in Remeda, Ramda allows the fallback value to be of any type, even those that are incompatible with the data type. It also allows the data type to be non-nullish; for those cases use the built-in Nullish coalescing operator ?? directly, or use when with isNullish and constant.

Nullish

const DATA: number | undefined | null;

// Ramda
R.defaultTo(456)(DATA);

// Remeda
defaultTo(DATA, 456);

NaN

const DATA = Number.NaN;

// Ramda
R.defaultTo(10)(DATA);

// Remeda
when(DATA, Number.isNaN, constant(10));

Both

const DATA: number | null | undefined;

// Ramda
R.defaultTo(10)(DATA);

// Remeda
when(
  DATA,
  (x) => x === undefined || x === null || Number.isNaN(x),
  constant(10),
);

Non-matching fallback

const DATA: string | null | undefined;

// Ramda
R.defaultTo(123)(DATA);

// Remeda
when(DATA, isNullish, constant(123));

// or natively
DATA ?? 123;

ifElse

when
  • Remeda supports both if-like statements, and if-else-like statements (which is what Ramda’s ifElse function supports); The former is done by using a predicate function and a mapper function, and the latter is done by wrapping both mappers with an object.
  • To support extra arguments Ramda requires one of the functions provided to provide full typing to all params, in Remeda this isn’t needed as the extra arguments would be inferred from the call site.

if-else

// Ramda
ifElse(predicate, onTrue, onFalse)(data);

// Remeda
when(data, predicate, { onTrue, onFalse });

// Or in a pipe
pipe(data, when(predicate, { onTrue, onFalse }));

if

ifElse(predicate, onTrue, identity)(data);

// Remeda
when(data, predicate, onTrue);

// Or in a pipe
pipe(data, when(predicate, onTrue));

extra args

// Ramda
const mapper = ifElse(
  (x: string | undefined, index: number) => x === undefined,
  (_, index) => `item_${index}`,
  identity,
);
map(data, mapper);

// Remeda
map(
  data,
  when(
    (x) => x === undefined,
    (_, index) => `item_${index}`,
  ),
);

not

isNot

The function only accepts boolean values, to support arbitrary values compose it with isTruthy.

Booleans

// Ramda
not(val);

// Remeda
isNot(val);

Arbitrary

// Ramda
not(val);

// Remeda
isNot(isTruthy(val));

Math

dec

subtract

Use subtract with an operand of 1.

// Ramda
dec(value);

// Remeda
subtract(value, 1);

inc

add

Use add with an operand of 1.

// Ramda
inc(value);

// Remeda
add(value, 1);

negate

multiply

Use multiply with an operand of -1.

// Ramda
negate(value);

// Remeda
multiply(value, -1);

Object

hasIn

hasProp

Own properties

// Ramda
hasIn("a", obj);

// Remeda
hasProp(obj, "a");

Inherited properties

// Ramda
hasIn("toString", {}); //=> true

// Remeda
hasProp({}, "toString"); //=> false

pathOr

prop

Compose prop with defaultTo.

// Ramda
R.pathOr("N/A", ["a", "b"], { a: { b: 2 } });

// Remeda
defaultTo(prop({ a: { b: 2 } }, "a", "b"), "N/A");

paths

prop

Compose paths using map and prop:

const DATA = { a: { b: 2 }, p: [{ q: 3 }] };
const PATHS = [
  ["a", "b"],
  ["p", 0, "q"],
] as const;

// Ramda
R.paths(PATHS, DATA);

// Remeda
map(PATHS, (path) => prop(DATA, ...path));

Relation

max

Not provided by Remeda.

The Ramda max function takes exactly 2 arguments. It is easily replicated using native JS operators.

// Ramda
max(a, b);

// Curried
const maxA = max(a);

// Native
a > b ? a : b;

const maxA = (b: number) => (a > b ? a : b);

maxBy

firstBy

The Remeda firstBy returns what would be the first item in an array if it was sorted by the order criteria (without actually sorting the array). Ramda’s maxBy could be rebuilt using firstBy by taking the mapping function in descending order, and wrapping the 2 arguments with an array.

// Ramda
maxBy(mapperFunc, a, b);

// Remeda
firstBy([a, b], [mapperFunc, "desc"]);

min

Not provided by Remeda.

The Ramda max function takes exactly 2 arguments. It is easily replicated using native JS operators.

// Ramda
min(a, b);

// Curried
const minA = min(a);

// Native
a < b ? a : b;

const minA = (b: number) => (a < b ? a : b);

minBy

firstBy

The Remeda firstBy returns what would be the first item in an array if it was sorted by the order criteria (without actually sorting the array). Ramda’s minBy could be rebuilt using firstBy by taking the mapping function in, and wrapping the 2 arguments with an array.

// Ramda
minBy(mapperFunc, a, b);

// Remeda
firstBy([a, b], mapperFunc);

sortWith

sortBy

Remeda’s sortBy also covers the use-case of sortWith using a simpler syntax to describe complex sorting logic; the function takes a variadic list of arguments instead of an array, and the sorting direction (ascending/descending) is determined by an optional tuple syntax for the operator.

const DATA = [
  {
    name: "clara",
    age: 40,
  },
  {
    name: "bob",
    age: 30,
  },
  {
    name: "alice",
    age: 40,
  },
];

// Ramda
sortWith([descend(prop("age")), ascend(prop("name"))])(DATA);

// Remeda
sortBy(DATA, [prop("age"), "desc"], prop("name"));

// Or in a pipe
pipe(DATA, sortBy([prop("age"), "desc"], prop("name")));

String

Type