Repository: remeda/remeda (ts)

Issue:
Add `add` and `multiply` functions.
These simple functions add and multiply two numbers.

This is useful when determining `sums` and `products` of arrays of numbers.

```
[1, 2, 3, 4].reduce(R.add); // 10
[1, 2, 3, 4].reduce(R.multiply); // 24
```

For completeness, it might also be worth adding `subtract` and `divide`.

All four functions are implemented in both Lodash and Ramda.

Separately, `sum` and `product` functions could also be useful. There's currently a `sumBy` function in Remeda, so `R.sum` could be as simple as `R.sumBy(R.identity)`.

Pull request:
feat: Add R.add, R.subtract, R.multiply and R.divide functions
This PR introduces four new number functions: `R.add`, `R.subtract`, `R.multiply` and `R.divide`.

Closes #439.

---

Make sure that you:

- [x] Typedoc added for new methods and updated for changed
- [x] Tests added for new methods and updated for changed
- [x] New methods added to `src/index.ts`
- [x] New methods added to `mapping.md`

---

<details><summary>We use semantic PR titles to automate the release process!</summary>

https://conventionalcommits.org

PRs should be titled following using the format: `< TYPE >(< scope >)?: description`

### Available Types:

- `feat`: new functions, and changes to a function's type that would impact users.
- `fix`: changes to the runtime behavior of an existing function, or refinements to it's type that shouldn't impact most users.
- `perf`: changes to function implementations that improve a functions _runtime_ performance.
- `refactor`: changes to function implementations that are neither `fix` nor `perf`
- `test`: tests-only changes (transparent to users of the function).
- `docs`: changes to the documentation of a function **or the documentation site**.
- `build`, `ci`, `style`, `chore`, and `revert`: are only relevant for the internals of the library.

For scope put the name of the function you are working on (either new or
existing).

</details>


Patch:
diff --git a/mapping.md b/mapping.md
index 95edbb0..e531bdb 100644
--- a/mapping.md
+++ b/mapping.md
@@ -8,6 +8,7 @@ documentation when migrating._
 
 | Remeda              | Lodash              | Ramda               |
 | ------------------- | ------------------- | ------------------- |
+| `add`               | `add`               | `add`               |
 | `addProp`           | `set`               | `set`               |
 | `allPass`           |                     | `allPass`           |
 | `anyPass`           |                     | `anyPass`           |
@@ -19,6 +20,7 @@ documentation when migrating._
 | `debounce`          | `debounce`          |                     |
 | `difference`        | `difference`        | `difference`        |
 | `differenceWith`    | `differenceWith`    | `differenceWith`    |
+| `divide`            | `divide`            | `divide`            |
 | `drop`              | `drop`              | `drop`              |
 | `dropLast`          | `dropRight`         | `dropLast`          |
 | `equals`            | `isEqual`           | `equals`            |
@@ -50,6 +52,7 @@ documentation when migrating._
 | `merge`             | `assign`            | `merge`             |
 | `mergeAll`          | `assign`            | `mergeAll`          |
 | `mergeDeep`         |                     | `mergeDeepRight`    |
+| `multiply`          | `multiply`          | `multiply`          |
 | `noop`              | `noop`              | `-`                 |
 | `objOf`             | `-`                 | `objOf`             |
 | `omit`              | `omit`              | `omit`              |
@@ -82,6 +85,7 @@ documentation when migrating._
 | `splitAt`           | `-`                 | `splitAt`           |
 | `splitWhen`         | `-`                 | `splitWhen`         |
 | `stringToPath`      | `toPath`            | `-`                 |
+| `subtract`          | `subtract`          | `subtract`          |
 | `sumBy`             | `sumBy`             | `-`                 |
 | `swapIndices`       | `-`                 | `swap`              |
 | `swapProps`         | `-`                 | `swap`              |
@@ -110,7 +114,6 @@ you are relying on when migrating._
 
 | Lodash     | Ramda    | TypeScript                    |
 | ---------- | -------- | ----------------------------- |
-| `add`      | `add`    | `(x, y) => x + y`             |
 |            | `append` | `(arr, val) => [...arr, val]` |
 | `constant` | `always` | `x => () => x`                |
 | `nth`      | `nth`    | `n => a[n]`                   |
diff --git a/src/add.ts b/src/add.ts
new file mode 100644
index 0000000..ea83d37
--- /dev/null
+++ b/src/add.ts
@@ -0,0 +1,39 @@
+import { purry } from './purry';
+
+/**
+ * Adds two numbers.
+ * @param value The number.
+ * @param addend The number to add to the value.
+ * @signature
+ *    R.add(value, addend);
+ * @example
+ *    R.add(10, 5) // => 15
+ *    R.add(10, -5) // => 5
+ *    R.reduce([1, 2, 3, 4], R.add, 0) // => 10
+ * @dataFirst
+ * @category Number
+ */
+export function add(value: number, addend: number): number;
+
+/**
+ * Adds two numbers.
+ * @param value The number.
+ * @param addend The number to add to the value.
+ * @signature
+ *    R.clamp(addend)(value);
+ * @example
+ *    R.add(5)(10) // => 15
+ *    R.add(-5)(10) // => 5
+ *    R.map([1, 2, 3, 4], R.add(1)) // => [2, 3, 4, 5]
+ * @dataLast
+ * @category Number
+ */
+export function add(addend: number): (value: number) => number;
+
+export function add() {
+  return purry(_add, arguments);
+}
+
+function _add(value: number, addend: number) {
+  return value + addend;
+}
diff --git a/src/divide.ts b/src/divide.ts
new file mode 100644
index 0000000..e9a60a2
--- /dev/null
+++ b/src/divide.ts
@@ -0,0 +1,37 @@
+import { purry } from './purry';
+
+/**
+ * Divides two numbers.
+ * @param value The number.
+ * @param divisor The number to divide the value by.
+ * @signature
+ *    R.divide(value, divisor);
+ * @example
+ *    R.divide(12, 3) // => 4
+ *    R.reduce([1, 2, 3, 4], R.divide, 24) // => 1
+ * @dataFirst
+ * @category Number
+ */
+export function divide(value: number, divisor: number): number;
+
+/**
+ * Divides two numbers.
+ * @param value The number.
+ * @param divisor The number to divide the value by.
+ * @signature
+ *    R.clamp(divisor)(value);
+ * @example
+ *    R.divide(3)(12) // => 4
+ *    R.map([2, 4, 6, 8], R.divide(2)) // => [1, 2, 3, 4]
+ * @dataLast
+ * @category Number
+ */
+export function divide(divisor: number): (value: number) => number;
+
+export function divide() {
+  return purry(_divide, arguments);
+}
+
+function _divide(value: number, divisor: number) {
+  return value / divisor;
+}
diff --git a/src/index.ts b/src/index.ts
index 721eecc..7a1f271 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,3 +1,4 @@
+export * from './add';
 export * from './addProp';
 export * from './allPass';
 export * from './anyPass';
@@ -11,6 +12,7 @@ export * from './createPipe';
 export * from './debounce';
 export * from './difference';
 export * from './differenceWith';
+export * from './divide';
 export * from './drop';
 export * from './dropLast';
 export * from './equals';
@@ -63,6 +65,7 @@ export * from './merge';
 export * from './mergeAll';
 export * from './mergeDeep';
 export * from './minBy';
+export * from './multiply';
 export * from './noop';
 export * from './objOf';
 export * from './omit';
@@ -96,6 +99,7 @@ export * from './splice';
 export * from './splitAt';
 export * from './splitWhen';
 export * from './stringToPath';
+export * from './subtract';
 export * from './sumBy';
 export * from './swapIndices';
 export * from './swapProps';
diff --git a/src/multiply.ts b/src/multiply.ts
new file mode 100644
index 0000000..d015d96
--- /dev/null
+++ b/src/multiply.ts
@@ -0,0 +1,37 @@
+import { purry } from './purry';
+
+/**
+ * Multiplies two numbers.
+ * @param value The number.
+ * @param multiplicand The number to multiply the value by.
+ * @signature
+ *    R.multiply(value, multiplicand);
+ * @example
+ *    R.multiply(3, 4) // => 12
+ *    R.reduce([1, 2, 3, 4], R.multiply, 1) // => 24
+ * @dataFirst
+ * @category Number
+ */
+export function multiply(value: number, multiplicand: number): number;
+
+/**
+ * Multiplies two numbers.
+ * @param value The number.
+ * @param multiplicand The number to multiply the value by.
+ * @signature
+ *    R.clamp(multiplicand)(value);
+ * @example
+ *    R.multiply(4)(3) // => 12
+ *    R.map([1, 2, 3, 4], R.multiply(2)) // => [2, 4, 6, 8]
+ * @dataLast
+ * @category Number
+ */
+export function multiply(multiplicand: number): (value: number) => number;
+
+export function multiply() {
+  return purry(_multiply, arguments);
+}
+
+function _multiply(value: number, multiplicand: number) {
+  return value * multiplicand;
+}
diff --git a/src/subtract.ts b/src/subtract.ts
new file mode 100644
index 0000000..c7ecf16
--- /dev/null
+++ b/src/subtract.ts
@@ -0,0 +1,39 @@
+import { purry } from './purry';
+
+/**
+ * Subtracts two numbers.
+ * @param value The number.
+ * @param subtrahend The number to subtract from the value.
+ * @signature
+ *    R.subtract(value, subtrahend);
+ * @example
+ *    R.subtract(10, 5) // => 5
+ *    R.subtract(10, -5) // => 15
+ *    R.reduce([1, 2, 3, 4], R.subtract, 20) // => 10
+ * @dataFirst
+ * @category Number
+ */
+export function subtract(value: number, subtrahend: number): number;
+
+/**
+ * Subtracts two numbers.
+ * @param value The number.
+ * @param subtrahend The number to subtract from the value.
+ * @signature
+ *    R.clamp(subtrahend)(value);
+ * @example
+ *    R.subtract(5)(10) // => 5
+ *    R.subtract(-5)(10) // => 15
+ *    R.map([1, 2, 3, 4], R.subtract(1)) // => [0, 1, 2, 3]
+ * @dataLast
+ * @category Number
+ */
+export function subtract(subtrahend: number): (value: number) => number;
+
+export function subtract() {
+  return purry(_subtract, arguments);
+}
+
+function _subtract(value: number, subtrahend: number) {
+  return value - subtrahend;
+}


Test patch:
diff --git a/src/add.test.ts b/src/add.test.ts
new file mode 100644
index 0000000..4f325bc
--- /dev/null
+++ b/src/add.test.ts
@@ -0,0 +1,11 @@
+import { add } from './add';
+
+test('data-first', () => {
+  expect(add(10, 5)).toEqual(15);
+  expect(add(10, -5)).toEqual(5);
+});
+
+test('data-last', () => {
+  expect(add(5)(10)).toEqual(15);
+  expect(add(-5)(10)).toEqual(5);
+});
diff --git a/src/divide.test.ts b/src/divide.test.ts
new file mode 100644
index 0000000..597067c
--- /dev/null
+++ b/src/divide.test.ts
@@ -0,0 +1,9 @@
+import { divide } from './divide';
+
+test('data-first', () => {
+  expect(divide(12, 3)).toEqual(4);
+});
+
+test('data-last', () => {
+  expect(divide(3)(12)).toEqual(4);
+});
diff --git a/src/multiply.test.ts b/src/multiply.test.ts
new file mode 100644
index 0000000..f8714ce
--- /dev/null
+++ b/src/multiply.test.ts
@@ -0,0 +1,9 @@
+import { multiply } from './multiply';
+
+test('data-first', () => {
+  expect(multiply(3, 4)).toEqual(12);
+});
+
+test('data-last', () => {
+  expect(multiply(4)(3)).toEqual(12);
+});
diff --git a/src/subtract.test.ts b/src/subtract.test.ts
new file mode 100644
index 0000000..52af423
--- /dev/null
+++ b/src/subtract.test.ts
@@ -0,0 +1,11 @@
+import { subtract } from './subtract';
+
+test('data-first', () => {
+  expect(subtract(10, 5)).toEqual(5);
+  expect(subtract(10, -5)).toEqual(15);
+});
+
+test('data-last', () => {
+  expect(subtract(5)(10)).toEqual(5);
+  expect(subtract(-5)(10)).toEqual(15);
+});