Repository: remeda/remeda
Pull request #574 (2024-03-17 08:59:27)

feat: deprecate `noop`, introduce `constant` and `doNothing`
The semantics (and name) for `noop` are more relevant for non-typed code where the difference between a function returning `void` and `undefined` are much less strict.

For Remeda, it makes more sense to have 2 functions that explicitly (and type-safely) define what the function does.

---

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>


codesandbox-ci[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/remeda/remeda/pr/574/builds/484448) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit fe42b8b0358a598787c4596f8fa672556034810c:

|Sandbox| Source |
|--|--|
|[remeda-example-vanilla](https://codesandbox.io/s/remeda-example-vanilla-mh69nj)| Configuration |


Patch:
diff --git a/eslint.config.mjs b/eslint.config.mjs
index d154e20..f6504cc 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -166,8 +166,7 @@ export default config(
       // recommended-typescript extension)
 
       // Correctness
-      // TODO: Requires manual fixes, enable in a separate PR.
-      "jsdoc/check-param-names": "off",
+      "jsdoc/check-param-names": "error",
       "jsdoc/check-tag-names": [
         "error",
         {
@@ -224,8 +223,7 @@ export default config(
       ],
       "jsdoc/require-description": "error",
       "jsdoc/require-example": ["warn", { enableFixer: false }],
-      // TODO: Requires manual fixes, enable in a separate PR.
-      "jsdoc/require-param": "off",
+      "jsdoc/require-param": "warn",
       // TODO: Requires manual fixes, enable in a separate PR.
       "jsdoc/require-returns": "off",
       // TODO: Requires manual fixes, enable in a separate PR.
@@ -426,9 +424,11 @@ export default config(
     files: ["src/_*.ts"],
     rules: {
       // Skip some JSDoc rules for internal-only functions:
+      "jsdoc/check-param-names": "off",
       "jsdoc/no-restricted-syntax": "off",
       "jsdoc/require-example": "off",
       "jsdoc/require-jsdoc": "off",
+      "jsdoc/require-param": "off",
     },
   },
 );
diff --git a/mapping.md b/mapping.md
index d2ba6e1..ac9ff6c 100644
--- a/mapping.md
+++ b/mapping.md
@@ -18,6 +18,7 @@ documentation when migrating._
 | [`clone`](https://remedajs.com/docs/#clone)                         | [`cloneDeep`](https://lodash.com/docs/4.17.15#cloneDeep)                 | [`clone`](https://ramdajs.com/docs/#clone)                         |
 | [`concat`](https://remedajs.com/docs/#concat)                       | [`concat`](https://lodash.com/docs/4.17.15#concat)                       | [`concat`](https://ramdajs.com/docs/#concat)                       |
 | [`conditional`](https://remedajs.com/docs/#conditional)             | [`cond`](https://lodash.com/docs/4.17.15#cond)                           | [`cond`](https://ramdajs.com/docs/#cond)                           |
+| [`constant`](https://remedajs.com/docs/#constant)                   | [`constant`](https://lodash.com/docs/4.17.15#constant)                   | [`always`](https://ramdajs.com/docs/#always)                       |
 | [`createPipe`](https://remedajs.com/docs/#createPipe)               |                                                                          |                                                                    |
 | [`debounce`](https://remedajs.com/docs/#debounce)                   | [`debounce`](https://lodash.com/docs/4.17.15#debounce)                   |                                                                    |
 | [`difference`](https://remedajs.com/docs/#difference)               | [`difference`](https://lodash.com/docs/4.17.15#difference)               | [`difference`](https://ramdajs.com/docs/#difference)               |
@@ -41,6 +42,7 @@ documentation when migrating._
 | [`forEach`](https://remedajs.com/docs/#forEach)                     | [`forEach`](https://lodash.com/docs/4.17.15#forEach)                     | [`forEach`](https://ramdajs.com/docs/#forEach)                     |
 | [`forEachObj`](https://remedajs.com/docs/#forEachObj)               | [`forEach`](https://lodash.com/docs/4.17.15#forEach)                     | [`forEachObjIndexed`](https://ramdajs.com/docs/#forEachObjIndexed) |
 | [`groupBy`](https://remedajs.com/docs/#groupBy)                     | [`groupBy`](https://lodash.com/docs/4.17.15#groupBy)                     | [`groupBy`](https://ramdajs.com/docs/#groupBy)                     |
+| [`hasSubobject`](https://remedajs.com/docs/#hasSubobject)           | [`isMatch`](https://lodash.com/docs/4.17.15#isMatch)                     | [`where`](https://ramdajs.com/docs/#where)                         |
 | [`identity`](https://remedajs.com/docs/#identity)                   | [`identity`](https://lodash.com/docs/4.17.15#identity)                   | [`identity`](https://ramdajs.com/docs/#identity)                   |
 | [`indexBy`](https://remedajs.com/docs/#indexBy)                     | [`keyBy`](https://lodash.com/docs/4.17.15#keyBy)                         | [`indexBy`](https://ramdajs.com/docs/#indexBy)                     |
 | [`intersection`](https://remedajs.com/docs/#intersection)           | [`intersection`](https://lodash.com/docs/4.17.15#intersection)           | [`intersection`](https://ramdajs.com/docs/#intersection)           |
@@ -65,7 +67,6 @@ documentation when migrating._
 | [`mergeAll`](https://remedajs.com/docs/#mergeAll)                   | [`assign`](https://lodash.com/docs/4.17.15#assign)                       | [`mergeAll`](https://ramdajs.com/docs/#mergeAll)                   |
 | [`mergeDeep`](https://remedajs.com/docs/#mergeDeep)                 |                                                                          | [`mergeDeepRight`](https://ramdajs.com/docs/#mergeDeepRight)       |
 | [`multiply`](https://remedajs.com/docs/#multiply)                   | [`multiply`](https://lodash.com/docs/4.17.15#multiply)                   | [`multiply`](https://ramdajs.com/docs/#multiply)                   |
-| [`noop`](https://remedajs.com/docs/#noop)                           | [`noop`](https://lodash.com/docs/4.17.15#noop)                           |                                                                    |
 | [`objOf`](https://remedajs.com/docs/#objOf)                         |                                                                          | [`objOf`](https://ramdajs.com/docs/#objOf)                         |
 | [`omit`](https://remedajs.com/docs/#omit)                           | [`omit`](https://lodash.com/docs/4.17.15#omit)                           | [`omit`](https://ramdajs.com/docs/#omit)                           |
 | [`omitBy`](https://remedajs.com/docs/#omitBy)                       | [`omitBy`](https://lodash.com/docs/4.17.15#omitBy)                       |                                                                    |
@@ -125,17 +126,17 @@ provide the exact functionality of the listed Lodash and Ramda functions.
 Be sure to consult each library's documentation and to check what features
 you are relying on when migrating._
 
-| Lodash     | Ramda    | TypeScript                        |
-| ---------- | -------- | --------------------------------- |
-|            | `append` | `(arr, val) => [...arr, val]`     |
-| `constant` | `always` | `x => () => x`                    |
-| `nth`      | `nth`    | `n => a[n]`                       |
-|            | `path`   | `a?.b?.c`                         |
-|            | `propEq` | `x => x.a === value`              |
-|            | `propOr` | `x => x.a ?? defaultValue`        |
-| `words`    |          | `str => str.split(/\s+/)`         |
-| `compact`  |          | `R.filter(R.isTruthy)`            |
-| `max`      | `max`    | `R.firstBy([R.identity, "desc"])` |
-| `maxBy`    | `maxBy`  | `R.firstBy([fn, "desc"])`         |
-| `min`      | `min`    | `R.firstBy(R.identity)`           |
-| `minBy`    | `minBy`  | `R.firstBy(fn)`                   |
+| Lodash    | Ramda    | TypeScript                        |
+| --------- | -------- | --------------------------------- |
+|           | `append` | `(arr, val) => [...arr, val]`     |
+| `nth`     | `nth`    | `n => a[n]`                       |
+|           | `path`   | `a?.b?.c`                         |
+|           | `propEq` | `x => x.a === value`              |
+|           | `propOr` | `x => x.a ?? defaultValue`        |
+| `words`   |          | `str => str.split(/\s+/)`         |
+| `compact` |          | `R.filter(R.isTruthy)`            |
+| `max`     | `max`    | `R.firstBy([R.identity, "desc"])` |
+| `maxBy`   | `maxBy`  | `R.firstBy([fn, "desc"])`         |
+| `min`     | `min`    | `R.firstBy(R.identity)`           |
+| `minBy`   | `minBy`  | `R.firstBy(fn)`                   |
+| `noop`    |          | `R.constant(undefined)`           |
diff --git a/src/add.ts b/src/add.ts
index 73bfa47..d86eca5 100644
--- a/src/add.ts
+++ b/src/add.ts
@@ -19,7 +19,6 @@ 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.add(addend)(value);
diff --git a/src/ceil.ts b/src/ceil.ts
index 3ebd70b..09046a8 100644
--- a/src/ceil.ts
+++ b/src/ceil.ts
@@ -25,7 +25,6 @@ export function ceil(value: number, precision: number): number;
  * 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.
  *
- * @param value - The number to round up.
  * @param precision - The precision to round up to. Must be an integer between -15 and 15.
  * @signature
  *    R.ceil(precision)(value);
diff --git a/src/clamp.ts b/src/clamp.ts
index 351fd69..eefc350 100644
--- a/src/clamp.ts
+++ b/src/clamp.ts
@@ -24,7 +24,6 @@ export function clamp(value: number, limits: Limits): number;
 /**
  * Clamp the given value within the inclusive min and max bounds.
  *
- * @param value - The number.
  * @param limits - The bounds limits.
  * @signature
  *    R.clamp({ min, max })(value);
diff --git a/src/conditional.ts b/src/conditional.ts
index c8140e8..d61565e 100644
--- a/src/conditional.ts
+++ b/src/conditional.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names, jsdoc/require-param -- we don't document the case params, it'd be redundant */
+
 import { purryOn } from "./_purryOn";
 
 type Case<In, Out, Thru extends In = In> = readonly [
@@ -26,7 +28,6 @@ type Case<In, Out, Thru extends In = In> = readonly [
  * is recommended for more precise type control when such type narrowing is
  * needed.
  *
- * @param data - The input data to be evaluated against the provided cases.
  * @param cases - A list of (up to 10) tuples, each defining a case. Each tuple
  * consists of a predicate (or a type-predicate) and a transformer function that
  * processes the data if its case matches.
diff --git a/src/constant.ts b/src/constant.ts
new file mode 100644
index 0000000..b31ce8f
--- /dev/null
+++ b/src/constant.ts
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ *
+ * @param value - The constant value that would be returned on every invocation.
+ * The value is not copied/cloned on every invocation so care should be taken
+ * with mutable objects (like arrays, objects, Maps, etc...).
+ * @signature
+ *   R.constant(value);
+ * @example
+ *   R.map([1, 2, 3], R.constant('a')); // => ['a', 'a', 'a']
+ *   R.map(
+ *     [1, 2, 3],
+ *     isDemoMode ? R.add(1) : R.constant(0),
+ *   ); // => [2, 3, 4] or [0, 0, 0]
+ * @dataLast
+ * @category Function
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export function constant<T>(value: T): (...args: any) => T {
+  return () => value;
+}
diff --git a/src/countBy.ts b/src/countBy.ts
index afc2f9a..b2cda80 100644
--- a/src/countBy.ts
+++ b/src/countBy.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names, jsdoc/require-param -- ignore for deprecated files */
+
 import { purry } from "./purry";
 import type { Pred, PredIndexed, PredIndexedOptional } from "./_types";
 
diff --git a/src/createPipe.ts b/src/createPipe.ts
index 52d1a57..cae7583 100644
--- a/src/createPipe.ts
+++ b/src/createPipe.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/require-param -- ignore for deprecated files */
+
 import { pipe } from "./pipe";
 
 /**
diff --git a/src/divide.ts b/src/divide.ts
index 6547467..2074195 100644
--- a/src/divide.ts
+++ b/src/divide.ts
@@ -18,7 +18,6 @@ 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.divide(divisor)(value);
diff --git a/src/doNothing.ts b/src/doNothing.ts
new file mode 100644
index 0000000..c30b6b2
--- /dev/null
+++ b/src/doNothing.ts
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ *
+ * @signature
+ *   R.doNothing();
+ * @example
+ *   myApi({ onSuccess: handleSuccess, onError: R.doNothing() });
+ *   myApi({ onSuccess: isDemoMode ? R.doNothing(): handleSuccess });
+ * @dataLast
+ * @category Function
+ */
+export function doNothing(): (
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  ...args: any
+) => void {
+  // Because the function does nothing we safely return the same function
+  // (pointer) and don't need to create a new one on every invocation.
+  return doesNothing;
+}
+
+function doesNothing(): void {
+  /* do nothing */
+}
diff --git a/src/drop.ts b/src/drop.ts
index 5654b8a..cb9aba9 100644
--- a/src/drop.ts
+++ b/src/drop.ts
@@ -20,7 +20,6 @@ export function drop<T>(array: ReadonlyArray<T>, n: number): Array<T>;
 /**
  * Removes first `n` elements from the `array`.
  *
- * @param array - The target array.
  * @param n - The number of elements to skip.
  * @signature
  *    R.drop(n)(array)
diff --git a/src/dropFirstBy.ts b/src/dropFirstBy.ts
index 4033dac..d587f22 100644
--- a/src/dropFirstBy.ts
+++ b/src/dropFirstBy.ts
@@ -30,7 +30,6 @@ export function dropFirstBy<T>(
  *
  * For the opposite operation (to keep `n` elements) see `takeFirstBy`.
  *
- * @param data - The input array.
  * @param n - The number of items to drop. If `n` is non-positive no items would be dropped and a *clone* of the input would be returned, if `n` is bigger then data.length no items would be returned.
  * @param rules - A variadic array of order rules defining the sorting criteria. Each order rule is a projection function that extracts a comparable value from the data. Sorting is based on these extracted values using the native `<` and `>` operators. Earlier rules take precedence over later ones. Use the syntax `[projection, "desc"]` for descending order.
  * @returns A subset of the input array.
diff --git a/src/dropLast.ts b/src/dropLast.ts
index 564709a..c50e772 100644
--- a/src/dropLast.ts
+++ b/src/dropLast.ts
@@ -17,7 +17,6 @@ export function dropLast<T>(array: ReadonlyArray<T>, n: number): Array<T>;
 /**
  * Removes last `n` elements from the `array`.
  *
- * @param array - The target array.
  * @param n - The number of elements to skip.
  * @signature
  *    R.dropLast(n)(array)
diff --git a/src/equals.ts b/src/equals.ts
index 35ea98d..b01df82 100644
--- a/src/equals.ts
+++ b/src/equals.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names -- ignore for deprecated files */
+
 import { purry } from "./purry";
 
 /**
diff --git a/src/evolve.ts b/src/evolve.ts
index 5e85ce6..dbc8ae1 100644
--- a/src/evolve.ts
+++ b/src/evolve.ts
@@ -65,7 +65,7 @@ type Evolved<T, E> = T extends object
  * Also, values included in `data` object will not be used
  * if its corresponding key does not exist in the `evolver` object.
  *
- * @param data - Object whose value is applied to the corresponding function
+ * @param object - Object whose value is applied to the corresponding function
  * that is defined in `evolver` at the same path.
  * @param evolver - Object that include functions that is applied to
  * the corresponding value of `data` object at the same path.
@@ -104,8 +104,6 @@ export function evolve<T extends object, E extends Evolver<T>>(
  * Also, values included in `data` object will not be used
  * if its corresponding key does not exist in the `evolver` object.
  *
- * @param data - Object whose value is applied to the corresponding function
- * that is defined in `evolver` at the same path.
  * @param evolver - Object that include functions that is applied to
  * the corresponding value of `data` object at the same path.
  * @signature
diff --git a/src/find.ts b/src/find.ts
index 02a1f9d..84ff279 100644
--- a/src/find.ts
+++ b/src/find.ts
@@ -7,7 +7,7 @@ import { purry } from "./purry";
 /**
  * Returns the value of the first element in the array where predicate is true, and undefined otherwise.
  *
- * @param items - The array.
+ * @param array - The array.
  * @param fn - The predicate.
  * @signature
  *    R.find(items, fn)
diff --git a/src/findIndex.ts b/src/findIndex.ts
index ae65ef2..93b6335 100644
--- a/src/findIndex.ts
+++ b/src/findIndex.ts
@@ -7,7 +7,7 @@ import { purry } from "./purry";
 /**
  * Returns the index of the first element in the array where predicate is true, and -1 otherwise.
  *
- * @param items - The array.
+ * @param array - The array.
  * @param fn - The predicate.
  * @signature
  *    R.findIndex(items, fn)
@@ -28,7 +28,6 @@ export function findIndex<T>(
 /**
  * Returns the index of the first element in the array where predicate is true, and -1 otherwise.
  *
- * @param items - The array.
  * @param fn - The predicate.
  * @signature
  *    R.findIndex(fn)(items)
diff --git a/src/findLastIndex.ts b/src/findLastIndex.ts
index da1e1de..0f4cecb 100644
--- a/src/findLastIndex.ts
+++ b/src/findLastIndex.ts
@@ -25,7 +25,6 @@ export function findLastIndex<T>(
 /**
  * Returns the index of the last element in the array where predicate is true, and -1 otherwise.
  *
- * @param array - The array.
  * @param fn - The predicate.
  * @signature
  *    R.findLastIndex(fn)(items)
diff --git a/src/first.ts b/src/first.ts
index 5823b31..57a31dd 100644
--- a/src/first.ts
+++ b/src/first.ts
@@ -29,7 +29,6 @@ export function first<T extends IterableContainer>(data: T): First<T>;
 /**
  * Gets the first element of `array`.
  *
- * @param data - The array.
  * @returns The first element of the array.
  * @signature
  *    R.first()(array)
diff --git a/src/firstBy.ts b/src/firstBy.ts
index a5ae5ac..5774cdb 100644
--- a/src/firstBy.ts
+++ b/src/firstBy.ts
@@ -20,7 +20,6 @@ type FirstBy<T extends IterableContainer> =
  *
  * Use `nthBy` if you need an element other that the first, or `takeFirstBy` if you more than just the first element.
  *
- * @param data - An array of items.
  * @param rules - A variadic array of order rules defining the sorting criteria. Each order rule is a projection function that extracts a comparable value from the data. Sorting is based on these extracted values using the native `<` and `>` operators. Earlier rules take precedence over later ones. Use the syntax `[projection, "desc"]` for descending order.
  * @returns The first element by the order criteria, or `undefined` if the array
  * is empty. (The function provides strong typing if the input type assures the
diff --git a/src/flatMap.ts b/src/flatMap.ts
index 51311cc..0061a88 100644
--- a/src/flatMap.ts
+++ b/src/flatMap.ts
@@ -23,7 +23,6 @@ export function flatMap<T, K>(
 /**
  * Map each element of an array using a defined callback function and flatten the mapped result.
  *
- * @param array - The array to map.
  * @param fn - The function mapper.
  * @signature
  *    R.flatMap(fn)(array)
diff --git a/src/flatten.ts b/src/flatten.ts
index 81104d2..68dceed 100644
--- a/src/flatten.ts
+++ b/src/flatten.ts
@@ -21,7 +21,6 @@ export function flatten<T>(items: ReadonlyArray<T>): Array<Flatten<T>>;
 /**
  * Flattens `array` a single level deep.
  *
- * @param items - The target array.
  * @signature
  *   R.flatten()(array)
  * @example
diff --git a/src/flattenDeep.ts b/src/flattenDeep.ts
index e73c444..fb7bb59 100644
--- a/src/flattenDeep.ts
+++ b/src/flattenDeep.ts
@@ -25,7 +25,6 @@ export function flattenDeep<T>(items: ReadonlyArray<T>): Array<FlattenDeep<T>>;
 /**
  * Recursively flattens `array`.
  *
- * @param items - The target array.
  * @signature
  *   R.flattenDeep()(array)
  * @example
diff --git a/src/floor.ts b/src/floor.ts
index e339a1b..45d78a2 100644
--- a/src/floor.ts
+++ b/src/floor.ts
@@ -25,7 +25,6 @@ export function floor(value: number, precision: number): number;
  * 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.
  *
- * @param value - The number to round down.
  * @param precision - The precision to round down to. Must be an integer between -15 and 15.
  * @signature
  *    R.floor(precision)(value);
diff --git a/src/fromPairs.ts b/src/fromPairs.ts
index afbd567..cfb01d9 100644
--- a/src/fromPairs.ts
+++ b/src/fromPairs.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names -- ignore for deprecated files */
+
 import type { IterableContainer } from "./_types";
 import { purry } from "./purry";
 
diff --git a/src/groupBy.ts b/src/groupBy.ts
index 457b760..18ea8b2 100644
--- a/src/groupBy.ts
+++ b/src/groupBy.ts
@@ -31,7 +31,6 @@ export function groupBy<T>(
 /**
  * Splits a collection into sets, grouped by the result of running each value through `fn`.
  *
- * @param fn - The grouping function.
  * @signature
  *    R.groupBy(fn)(array)
  * @example
diff --git a/src/hasAtLeast.ts b/src/hasAtLeast.ts
index b0e8606..76accc1 100644
--- a/src/hasAtLeast.ts
+++ b/src/hasAtLeast.ts
@@ -39,7 +39,6 @@ export function hasAtLeast<T, N extends number>(
  * refines the output type accordingly so that those indices are defined when
  * accessing the array even when using typescript's 'noUncheckedIndexAccess'.
  *
- * @param data - The input array.
  * @param minimum - The minimum number of elements the array must have.
  * @returns True if the array's length is *at least* `minimum`.
  * @signature
diff --git a/src/hasSubObject.ts b/src/hasSubObject.ts
new file mode 100644
index 0000000..9fc4b39
--- /dev/null
+++ b/src/hasSubObject.ts
@@ -0,0 +1,65 @@
+import { isDeepEqual } from "./isDeepEqual";
+import { purry } from "./purry";
+import type { Simplify } from "./type-fest/simplify";
+
+/**
+ * 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`.
+ *
+ * @param data - The object to test.
+ * @param subObject - The sub-object to test against.
+ * @signature
+ *    R.hasSubObject(data, subObject)
+ * @example
+ *    R.hasSubObject({ a: 1, b: 2, c: 3 }, { a: 1, c: 3 }) //=> true
+ *    R.hasSubObject({ a: 1, b: 2, c: 3 }, { b: 4 }) //=> false
+ *    R.hasSubObject({ a: 1, b: 2, c: 3 }, {}) //=> true
+ * @dataFirst
+ * @category Guard
+ */
+export function hasSubObject<T, S extends Partial<T>>(
+  data: T,
+  subObject: S,
+): // TODO: want to use data is Merge<T, S> here, but it's a typescript error. fix after we allow @ts-expect-error in the build process
+data is Simplify<S & T>;
+
+/**
+ * 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`.
+ *
+ * @param subObject - The sub-object to test against.
+ * @signature
+ *    R.hasSubObject(subObject)(data)
+ * @example
+ *    R.hasSubObject({ a: 1, c: 3 })({ a: 1, b: 2, c: 3 }) //=> true
+ *    R.hasSubObject({ b: 4 })({ a: 1, b: 2, c: 3 }) //=> false
+ *    R.hasSubObject({})({ a: 1, b: 2, c: 3 }) //=> true
+ * @dataLast
+ * @category Guard
+ */
+export function hasSubObject<T, S extends Partial<T>>(
+  subObject: S,
+): (data: T) => data is Simplify<S & T>;
+
+export function hasSubObject(): unknown {
+  return purry(_hasSubObject, arguments);
+}
+
+function _hasSubObject<T, S extends Partial<T>>(
+  data: T,
+  subObject: S,
+): data is Simplify<S & T> {
+  for (const key of Object.keys(subObject)) {
+    if (!Object.prototype.hasOwnProperty.call(data, key)) {
+      return false;
+    }
+
+    // @ts-expect-error [ts7053] - key is in both subObject and data:
+    if (!isDeepEqual(subObject[key], data[key])) {
+      return false;
+    }
+  }
+  return true;
+}
diff --git a/src/identity.ts b/src/identity.ts
index 1215d0d..6fd0bf8 100644
--- a/src/identity.ts
+++ b/src/identity.ts
@@ -8,6 +8,7 @@
 /**
  * A function that always returns the param passed to it.
  *
+ * @param value - The param to return.
  * @signature
  *    R.identity(data)
  * @example
diff --git a/src/index.ts b/src/index.ts
index c556fa3..3a76d0b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -9,12 +9,14 @@ export * from "./clone";
 export * from "./compact";
 export * from "./concat";
 export * from "./conditional";
+export * from "./constant";
 export * from "./countBy";
 export * from "./createPipe";
 export * from "./debounce";
 export * from "./difference";
 export * from "./differenceWith";
 export * from "./divide";
+export * from "./doNothing";
 export * from "./drop";
 export * from "./dropFirstBy";
 export * from "./dropLast";
@@ -39,6 +41,7 @@ export * from "./forEachObj";
 export * from "./fromPairs";
 export * from "./groupBy";
 export * from "./hasAtLeast";
+export * from "./hasSubObject";
 export * from "./identity";
 export * from "./indexBy";
 export * from "./intersection";
diff --git a/src/indexBy.ts b/src/indexBy.ts
index 529304f..3174f08 100644
--- a/src/indexBy.ts
+++ b/src/indexBy.ts
@@ -28,7 +28,6 @@ export function indexBy<T>(
  * (casted to a string). Use the strict version to maintain the given key's type, so
  * long as it is a valid `PropertyKey`.
  *
- * @param array - The array.
  * @param fn - The indexing function.
  * @signature
  *    R.indexBy(fn)(array)
diff --git a/src/intersection.ts b/src/intersection.ts
index a22494b..eaf2511 100644
--- a/src/intersection.ts
+++ b/src/intersection.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names, jsdoc/require-param -- ignore for deprecated files */
+
 import { _reduceLazy } from "./_reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
diff --git a/src/invert.ts b/src/invert.ts
index fb071ce..ef2979f 100644
--- a/src/invert.ts
+++ b/src/invert.ts
@@ -23,7 +23,6 @@ export function invert<T extends object>(object: T): Inverted<T>;
  * Returns an object whose keys are values are swapped. If the object contains duplicate values,
  * subsequent values will overwrite previous values.
  *
- * @param object - The object.
  * @signature
  *    R.invert()(object)
  * @example
diff --git a/src/isDeepEqual.ts b/src/isDeepEqual.ts
index 95ef5f2..20b2f98 100644
--- a/src/isDeepEqual.ts
+++ b/src/isDeepEqual.ts
@@ -41,7 +41,6 @@ export function isDeepEqual<T, S extends T = T>(data: T, other: S): data is S;
  * The result would be narrowed to the second value so that the function can be
  * used as a type guard.
  *
- * @param data - The first value to compare.
  * @param other - The second value to compare.
  * @signature
  *    R.isDeepEqual(other)(data)
diff --git a/src/isIncludedIn.ts b/src/isIncludedIn.ts
index 3b86a66..7c20531 100644
--- a/src/isIncludedIn.ts
+++ b/src/isIncludedIn.ts
@@ -39,7 +39,6 @@ export function isIncludedIn<T, S extends T>(
  * Notice that unlike most functions, this function takes a generic item as it's
  * data and **an array** as it's parameter.
  *
- * @param data - The item that is checked.
  * @param container - The items that are checked against.
  * @returns A narrowed version of the input data on success, `false` otherwise.
  * @signature
diff --git a/src/join.ts b/src/join.ts
index 6927ac4..12d70c1 100644
--- a/src/join.ts
+++ b/src/join.ts
@@ -61,7 +61,6 @@ export function join<
  * 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).
  *
- * @param data - The array to join.
  * @param glue - The string to put in between every two elements.
  * @signature
  *    R.join(glue)(data)
diff --git a/src/keys.ts b/src/keys.ts
index b7ac8bb..2b407fb 100644
--- a/src/keys.ts
+++ b/src/keys.ts
@@ -32,7 +32,6 @@ export function keys(
 /**
  * Returns a new array containing the keys of the array or object.
  *
- * @param source - Either an array or an object.
  * @signature
  *    R.keys()(source)
  *    R.keys.strict()(source)
diff --git a/src/last.ts b/src/last.ts
index 545bbad..769e704 100644
--- a/src/last.ts
+++ b/src/last.ts
@@ -20,7 +20,6 @@ export function last<T>(array: ReadonlyArray<T>): T | undefined;
 /**
  * Gets the last element of `array`.
  *
- * @param array - The array.
  * @signature
  *    R.last()(array)
  * @example
diff --git a/src/length.ts b/src/length.ts
index e438385..fca463e 100644
--- a/src/length.ts
+++ b/src/length.ts
@@ -18,7 +18,6 @@ export function length<T>(items: Enumerable<T>): number;
 /**
  * Counts values of the collection or iterable.
  *
- * @param items - The input data.
  * @signature
  *    R.length()(array)
  * @example
diff --git a/src/merge.ts b/src/merge.ts
index 66a9143..434fe81 100644
--- a/src/merge.ts
+++ b/src/merge.ts
@@ -35,9 +35,6 @@ export function merge<T, Source>(data: T, source: Source): Merge<T, Source>;
  *
  * Equivalent to `{ ...data, ...source }`.
  *
- * @param data - The destination object, serving as the basis for the merge.
- * Properties from this object are included in the new object, but will be
- * overwritten by properties from the source object with matching keys.
  * @param source - The source object, whose properties will be included in the
  * new object. If properties in this object share keys with properties in the
  * destination object, the values from the source object will be used in the
diff --git a/src/mergeDeep.ts b/src/mergeDeep.ts
index 23d2cfd..afebb5b 100644
--- a/src/mergeDeep.ts
+++ b/src/mergeDeep.ts
@@ -22,7 +22,6 @@ export function mergeDeep<
 /**
  * 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)`).
  *
- * @param destination - The object to merge into. In general, this object would have it's values overridden.
  * @param source - The object to merge from. In general, shared keys would be taken from this object.
  * @returns The merged object.
  * @signature
diff --git a/src/multiply.ts b/src/multiply.ts
index ef5fb71..0f488b4 100644
--- a/src/multiply.ts
+++ b/src/multiply.ts
@@ -18,7 +18,6 @@ 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.multiply(multiplicand)(value);
diff --git a/src/noop.ts b/src/noop.ts
index 5368958..a7f69e2 100644
--- a/src/noop.ts
+++ b/src/noop.ts
@@ -1,10 +1,13 @@
 /**
  * A function that returns always `undefined`.
  *
+ * ! **DEPRECATED**: Use `R.constant(undefined)`, or `R.doNothing()` if the function doesn't need to return a value. Will be removed in V2!
+ *
  * @signature
  *    R.noop()
  * @example
  *    onSomething(R.noop)
- * @category Function
+ * @category Deprecated
+ * @deprecated Use `R.constant(undefined)`, or `R.doNothing()` if the function doesn't need to return a value. Will be removed in V2!
  */
 export const noop = (): undefined => undefined;
diff --git a/src/nthBy.ts b/src/nthBy.ts
index 6411a9d..1275aaa 100644
--- a/src/nthBy.ts
+++ b/src/nthBy.ts
@@ -34,7 +34,6 @@ export function nthBy<T extends IterableContainer>(
  *
  * 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`.
  *
- * @param data - The input array.
  * @param index - The zero-based index for selecting the element in the sorted order. Negative indices count backwards from the end.
  * @param rules - A variadic array of order rules defining the sorting criteria. Each order rule is a projection function that extracts a comparable value from the data. Sorting is based on these extracted values using the native `<` and `>` operators. Earlier rules take precedence over later ones. Use the syntax `[projection, "desc"]` for descending order.
  * @returns The element at the specified index in the sorted order, or `undefined` if the index is out of bounds.
diff --git a/src/omit.ts b/src/omit.ts
index a3649f9..18bf975 100644
--- a/src/omit.ts
+++ b/src/omit.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names -- ignore for deprecated files */
+
 import { fromPairs } from "./fromPairs";
 import { hasAtLeast } from "./hasAtLeast";
 import { purry } from "./purry";
diff --git a/src/only.ts b/src/only.ts
index 41c8a75..210b235 100644
--- a/src/only.ts
+++ b/src/only.ts
@@ -30,7 +30,6 @@ export function only<T extends IterableContainer>(array: Readonly<T>): Only<T>;
 /**
  * Returns the first and only element of `array`, or undefined otherwise.
  *
- * @param array - The target array.
  * @signature
  *    R.only()(array)
  * @example
diff --git a/src/pathOr.ts b/src/pathOr.ts
index f7fe30f..26c3aef 100644
--- a/src/pathOr.ts
+++ b/src/pathOr.ts
@@ -111,7 +111,6 @@ export function pathOr<
 /**
  * Gets the value at `path` of `object`. If the resolved value is `undefined`, the `defaultValue` is returned in its place.
  *
- * @param object - The target object.
  * @param path - The path of the property to get.
  * @param defaultValue - The default value.
  * @signature R.pathOr(array, defaultValue)(object)
diff --git a/src/pipe.ts b/src/pipe.ts
index 7fadaf4..1655972 100644
--- a/src/pipe.ts
+++ b/src/pipe.ts
@@ -1,4 +1,5 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
+/* eslint-disable jsdoc/check-param-names, jsdoc/require-param -- we don't document the op params, it'd be redundant */
 
 export type LazyEvaluator<T = unknown, R = T> = (
   item: T,
diff --git a/src/purry.ts b/src/purry.ts
index ca446c7..05dd0f1 100644
--- a/src/purry.ts
+++ b/src/purry.ts
@@ -25,6 +25,7 @@ type MaybeLazyFunction = {
  *
  * @param fn - The function to purry.
  * @param args - The arguments.
+ * @param lazyFactory - A lazy version of the function to purry.
  * @signature R.purry(fn, arguments);
  * @example
  *    function _findIndex(array, fn) {
diff --git a/src/randomString.ts b/src/randomString.ts
index b46e096..c716c80 100644
--- a/src/randomString.ts
+++ b/src/randomString.ts
@@ -22,7 +22,6 @@ export function randomString(length: number): string;
 /**
  * Random a non-cryptographic random string from characters a-zA-Z0-9.
  *
- * @param length - The length of the random string.
  * @returns The random string.
  * @signature
  *   R.randomString()(length)
diff --git a/src/rankBy.ts b/src/rankBy.ts
index c0f50d5..bbbf35a 100644
--- a/src/rankBy.ts
+++ b/src/rankBy.ts
@@ -29,7 +29,6 @@ export function rankBy<T>(
 /**
  * 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)`.
  *
- * @param data - The input array.
  * @param item - The item whose rank is to be determined.
  * @param rules - A variadic array of order rules defining the sorting criteria. Each order rule is a projection function that extracts a comparable value from the data. Sorting is based on these extracted values using the native `<` and `>` operators. Earlier rules take precedence over later ones. Use the syntax `[projection, "desc"]` for descending order.
  * @returns The rank of the item in the sorted array in the range [0..data.length].
diff --git a/src/reduce.ts b/src/reduce.ts
index e389b34..bbb2d81 100644
--- a/src/reduce.ts
+++ b/src/reduce.ts
@@ -3,7 +3,7 @@ import { purry } from "./purry";
 /**
  * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
  *
- * @param array - The array to reduce.
+ * @param items - The array to reduce.
  * @param fn - The callback function.
  * @param initialValue - The initial value to use as an accumulator value in the callback function.
  * @signature
diff --git a/src/reject.ts b/src/reject.ts
index 567aa78..fa1a46f 100644
--- a/src/reject.ts
+++ b/src/reject.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names -- ignore for deprecated files */
+
 import { _reduceLazy } from "./_reduceLazy";
 import { _toLazyIndexed } from "./_toLazyIndexed";
 import type { Pred, PredIndexed, PredIndexedOptional } from "./_types";
diff --git a/src/reverse.ts b/src/reverse.ts
index 2c3675c..7bcfb94 100644
--- a/src/reverse.ts
+++ b/src/reverse.ts
@@ -29,7 +29,6 @@ export function reverse<T extends ReadonlyArray<unknown>>(array: T): Reverse<T>;
 /**
  * Reverses array.
  *
- * @param array - The array.
  * @signature
  *    R.reverse()(array);
  * @example
diff --git a/src/round.ts b/src/round.ts
index b94a190..c12717b 100644
--- a/src/round.ts
+++ b/src/round.ts
@@ -25,7 +25,6 @@ export function round(value: number, precision: number): number;
  * 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.
  *
- * @param value - The number to round.
  * @param precision - The precision to round to. Must be an integer between -15 and 15.
  * @signature
  *    R.round(precision)(value);
diff --git a/src/sample.ts b/src/sample.ts
index 1c4a4e1..3521dea 100644
--- a/src/sample.ts
+++ b/src/sample.ts
@@ -57,7 +57,7 @@ type SampledLiteral<
  * If you need to get a shuffled response you can pipe the shuffle function
  * after this one.
  *
- * @param array - The array.
+ * @param data - The array.
  * @param sampleSize - The number of elements to take.
  * @signature
  *    R.sample(array, sampleSize)
@@ -84,7 +84,6 @@ export function sample<T extends IterableContainer, N extends number = number>(
  * If you need to get a shuffled response you can pipe the shuffle function
  * after this one.
  *
- * @param array - The array.
  * @param sampleSize - The number of elements to take.
  * @signature
  *    R.sample(sampleSize)(array)
diff --git a/src/setPath.ts b/src/setPath.ts
index f7a953a..2a51007 100644
--- a/src/setPath.ts
+++ b/src/setPath.ts
@@ -24,7 +24,6 @@ export function setPath<T, TPath extends Array<PropertyKey> & Path<T>>(
 /**
  * Sets the value at `path` of `object`.
  *
- * @param obj - The target method.
  * @param path - The array of properties.
  * @param value - The value to set.
  * @signature
diff --git a/src/sliceString.ts b/src/sliceString.ts
index 9788e54..81f9997 100644
--- a/src/sliceString.ts
+++ b/src/sliceString.ts
@@ -5,7 +5,6 @@
  * `String.prototype.slice` directly. This function doesn't provide any type
  * improvements over the built-in types.
  *
- * @param string - The string to slice.
  * @param indexStart - The index of the first character to include in the returned substring.
  * @param indexEnd - (optional) The index of the first character to exclude from the returned substring.
  * @signature
diff --git a/src/sortBy.ts b/src/sortBy.ts
index 0543c15..0180cd8 100644
--- a/src/sortBy.ts
+++ b/src/sortBy.ts
@@ -19,7 +19,6 @@ import type {
  * * `rankBy` === `sortedIndex(sortBy(data, ...rules), item)`, O(n).
  * Refer to the docs for more details.
  *
- * @param data - The input array.
  * @param rules - A variadic array of order rules defining the sorting criteria. Each order rule is a projection function that extracts a comparable value from the data. Sorting is based on these extracted values using the native `<` and `>` operators. Earlier rules take precedence over later ones. Use the syntax `[projection, "desc"]` for descending order.
  * @returns A shallow copy of the input array sorted by the provided rules.
  * @signature
@@ -55,8 +54,8 @@ export function sortBy<T>(
  * * `rankBy` === `sortedIndex(sortBy(data, ...rules), item)`, O(n).
  * Refer to the docs for more details.
  *
- * @param data - The input array.
- * @param rules - A variadic array of order rules defining the sorting criteria. Each order rule is a projection function that extracts a comparable value from the data. Sorting is based on these extracted values using the native `<` and `>` operators. Earlier rules take precedence over later ones. Use the syntax `[projection, "desc"]` for descending order.
+ * @param array - The input array.
+ * @param sortRules - A variadic array of order rules defining the sorting criteria. Each order rule is a projection function that extracts a comparable value from the data. Sorting is based on these extracted values using the native `<` and `>` operators. Earlier rules take precedence over later ones. Use the syntax `[projection, "desc"]` for descending order.
  * @returns A shallow copy of the input array sorted by the provided rules.
  * @signature
  *    R.sortBy(data, ...rules)
diff --git a/src/sortedIndex.ts b/src/sortedIndex.ts
index c3cf03c..a3c77ce 100644
--- a/src/sortedIndex.ts
+++ b/src/sortedIndex.ts
@@ -32,7 +32,6 @@ export function sortedIndex<T>(data: ReadonlyArray<T>, item: T): number;
  *
  * Runs in O(logN) time.
  *
- * @param data - The (ascending) sorted array.
  * @param item - The item to insert.
  * @returns Insertion index (In the range 0..array.length).
  * @signature
diff --git a/src/sortedIndexBy.ts b/src/sortedIndexBy.ts
index 4f581c5..45150cd 100644
--- a/src/sortedIndexBy.ts
+++ b/src/sortedIndexBy.ts
@@ -43,7 +43,6 @@ export function sortedIndexBy<T>(
  *
  * Runs in O(logN) time.
  *
- * @param data - The (ascending) sorted array.
  * @param item - The item to insert.
  * @param valueFunction - All comparisons would be performed on the result of
  * calling this function on each compared item. Preferably this function should
@@ -64,28 +63,6 @@ export function sortedIndexBy<T>(
   valueFunction: (item: T) => NonNullable<unknown>,
 ): (data: ReadonlyArray<T>) => number;
 
-/**
- * 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.
- *
- * @param data - The (ascending) sorted array.
- * @param item - The item to insert.
- * @param valueFunction - All comparisons would be performed on the result of
- * calling this function on each compared item. Preferably this function should
- * return a `number` or `string`. This function should be the same as the one
- * provided to sortBy to sort the array.
- * @returns Insertion index (In the range 0..array.length - 1).
- * @signature
- *    R.sortedIndexBy(item, valueFunction)(data)
- * @example
- *    R.pipe([{age:20},{age:22}], R.sortedIndexBy({age:21},prop('age'))) // => 1
- * @dataLast
- * @category Array
- * @see sortedIndex, sortedIndexWith, sortedLastIndex, sortedLastIndexBy
- */
 export function sortedIndexBy(): unknown {
   return purry(sortedIndexByImplementation, arguments);
 }
diff --git a/src/sortedIndexWith.ts b/src/sortedIndexWith.ts
index a9629e2..72140d9 100644
--- a/src/sortedIndexWith.ts
+++ b/src/sortedIndexWith.ts
@@ -48,7 +48,6 @@ export function sortedIndexWith<T>(
  * for a specific item in a sorted array, and it could be used to perform
  * similar efficient searches.
  *
- * @param data - Array, "sorted" by `predicate`.
  * @param predicate - A predicate which also defines the array's order.
  * @returns Index (In the range 0..data.length).
  * @signature
diff --git a/src/sortedLastIndex.ts b/src/sortedLastIndex.ts
index 50ec2fe..74cf850 100644
--- a/src/sortedLastIndex.ts
+++ b/src/sortedLastIndex.ts
@@ -32,7 +32,6 @@ export function sortedLastIndex<T>(data: ReadonlyArray<T>, item: T): number;
  *
  * Runs in O(logN) time.
  *
- * @param data - The (ascending) sorted array.
  * @param item - The item to insert.
  * @returns Insertion index (In the range 0..data.length).
  * @signature
diff --git a/src/sortedLastIndexBy.ts b/src/sortedLastIndexBy.ts
index a04480b..53de627 100644
--- a/src/sortedLastIndexBy.ts
+++ b/src/sortedLastIndexBy.ts
@@ -43,7 +43,6 @@ export function sortedLastIndexBy<T>(
  *
  * Runs in O(logN) time.
  *
- * @param data - The (ascending) sorted array.
  * @param item - The item to insert.
  * @param valueFunction - All comparisons would be performed on the result of
  * calling this function on each compared item. Preferably this function should
diff --git a/src/splice.ts b/src/splice.ts
index 9dcbf88..927937c 100644
--- a/src/splice.ts
+++ b/src/splice.ts
@@ -25,7 +25,6 @@ export function splice<T>(
 /**
  * Removes elements from an array and, inserts new elements in their place.
  *
- * @param items - The array to splice.
  * @param start - The index from which to start removing elements.
  * @param deleteCount - The number of elements to remove.
  * @param replacement - The elements to insert into the array in place of the deleted elements.
diff --git a/src/splitAt.ts b/src/splitAt.ts
index e84c55b..26423ff 100644
--- a/src/splitAt.ts
+++ b/src/splitAt.ts
@@ -21,7 +21,6 @@ export function splitAt<T>(
 /**
  * Splits a given array at a given index.
  *
- * @param array - The array to split.
  * @param index - The index to split at.
  * @signature
  *    R.splitAt(index)(array)
diff --git a/src/subtract.ts b/src/subtract.ts
index 7275924..d7b9a9e 100644
--- a/src/subtract.ts
+++ b/src/subtract.ts
@@ -19,7 +19,6 @@ 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.subtract(subtrahend)(value);
diff --git a/src/takeFirstBy.ts b/src/takeFirstBy.ts
index 0805944..9a36862 100644
--- a/src/takeFirstBy.ts
+++ b/src/takeFirstBy.ts
@@ -30,7 +30,6 @@ export function takeFirstBy<T>(
  *
  * For the opposite operation (to drop `n` elements) see `dropFirstBy`.
  *
- * @param data - The input array.
  * @param n - The number of items to take. If `n` is non-positive no items would be returned, if `n` is bigger then data.length a *clone* of `data` would be returned.
  * @param rules - A variadic array of order rules defining the sorting criteria. Each order rule is a projection function that extracts a comparable value from the data. Sorting is based on these extracted values using the native `<` and `>` operators. Earlier rules take precedence over later ones. Use the syntax `[projection, "desc"]` for descending order.
  * @returns A subset of the input array.
diff --git a/src/times.ts b/src/times.ts
index 11b890d..8995956 100644
--- a/src/times.ts
+++ b/src/times.ts
@@ -23,7 +23,6 @@ export function times<T>(count: number, fn: (n: number) => T): Array<T>;
  * and is gradually incremented to `n - 1`.
  *
  * @param fn - The function to invoke. Passed one argument, the current value of `n`.
- * @param count - A value between `0` and `n - 1`. Increments after each function call.
  * @returns An array containing the return values of all calls to `fn`.
  * @example times(identity)(5); //=> [0, 1, 2, 3, 4]
  * @dataLast
diff --git a/src/toPairs.ts b/src/toPairs.ts
index c2d5f30..05ca2d2 100644
--- a/src/toPairs.ts
+++ b/src/toPairs.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names -- ignore for deprecated files */
+
 import { purry } from "./purry";
 
 /**
diff --git a/src/uniq.ts b/src/uniq.ts
index 3941fc0..161a931 100644
--- a/src/uniq.ts
+++ b/src/uniq.ts
@@ -1,3 +1,5 @@
+/* eslint-disable jsdoc/check-param-names -- ignore for deprecated files */
+
 import { _reduceLazy } from "./_reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
diff --git a/src/values.ts b/src/values.ts
index 0de0c01..ce36760 100644
--- a/src/values.ts
+++ b/src/values.ts
@@ -29,7 +29,6 @@ export function values<T extends object>(data: T): Values<T>;
 /**
  * Returns a new array containing the values of the array or object.
  *
- * @param source - Either an array or an object.
  * @signature
  *    R.values()(source)
  * @example


Test patch:
diff --git a/src/constant.test.ts b/src/constant.test.ts
new file mode 100644
index 0000000..c79d1ef
--- /dev/null
+++ b/src/constant.test.ts
@@ -0,0 +1,93 @@
+import { add } from "./add";
+import { constant } from "./constant";
+import { map } from "./map";
+import { pipe } from "./pipe";
+import { sliceString } from "./sliceString";
+import { times } from "./times";
+
+describe("runtime", () => {
+  test("works", () => {
+    const one = constant(1);
+    expect(one()).toBe(1);
+  });
+
+  test("returns identity (doesn't clone)", () => {
+    const obj = {} as { a?: boolean };
+    const emptyObj = constant(obj);
+    const firstInvocation = emptyObj();
+    expect(firstInvocation).toEqual({});
+    expect(firstInvocation).toBe(obj);
+
+    obj.a = true;
+
+    expect(firstInvocation).toEqual({ a: true });
+
+    expect(emptyObj()).toEqual({ a: true });
+    expect(emptyObj()).toBe(obj);
+  });
+
+  test("works with more than one argument", () => {
+    const one = constant(1);
+    expect(one(1)).toBe(1);
+    expect(one(1, 2)).toBe(1);
+    expect(one(1, 2, "a")).toBe(1);
+    expect(one(undefined)).toBe(1);
+    expect(one(["a"])).toBe(1);
+  });
+
+  test("can be put in a pipe", () => {
+    expect(pipe([1, 2, 3], constant([2, 3, 4]), map(add(1)))).toEqual([
+      3, 4, 5,
+    ]);
+  });
+
+  test("can completely change the type of the pipe", () => {
+    expect(pipe([1, 2, 3], constant("hello world"), sliceString(0, 4))).toEqual(
+      "hell",
+    );
+  });
+
+  test("can be used as a fill function (with times)", () => {
+    expect(times(10, constant("a"))).toEqual([
+      "a",
+      "a",
+      "a",
+      "a",
+      "a",
+      "a",
+      "a",
+      "a",
+      "a",
+      "a",
+    ]);
+  });
+});
+
+describe("typing", () => {
+  test("supported in any api", () => {
+    mockApi({
+      onMixOfParams: constant(1),
+      onNoParams: constant(true),
+      onVariadicParams: constant("cat"),
+    });
+  });
+
+  test("doesn't break return typing", () => {
+    mockApi({
+      // @ts-expect-error [ts2322] - string is not a number.
+      onMixOfParams: constant("hello"),
+      // @ts-expect-error [ts2322] - number is not a boolean.
+      onNoParams: constant(123),
+      // @ts-expect-error [ts2322] - "mouse" is not a cat or a dog.
+      onVariadicParams: constant("mouse"),
+    });
+  });
+});
+
+function mockApi(_options: {
+  readonly onMixOfParams: (result: string, isOptionalBoolean?: true) => number;
+  readonly onNoParams: () => boolean;
+  readonly onVariadicParams: (...args: ReadonlyArray<string>) => "cat" | "dog";
+}): void {
+  /* do nothing */
+}
diff --git a/src/doNothing.test.ts b/src/doNothing.test.ts
new file mode 100644
index 0000000..3f06b5e
--- /dev/null
+++ b/src/doNothing.test.ts
@@ -0,0 +1,35 @@
+import { doNothing } from "./doNothing";
+
+describe("runtime", () => {
+  test("works", () => {
+    const doesNothing = doNothing();
+    doesNothing();
+  });
+
+  test("works with more than one argument", () => {
+    const doesNothing = doNothing();
+    doesNothing(1);
+    doesNothing(1, 2);
+    doesNothing(1, 2, "a");
+    doesNothing(undefined);
+    doesNothing(["a"]);
+  });
+});
+
+describe("typing", () => {
+  test("supported in any api", () => {
+    mockApi({
+      onMixOfParams: doNothing(),
+      onNoParams: doNothing(),
+      onVariadicParams: doNothing(),
+    });
+  });
+});
+
+function mockApi(_options: {
+  readonly onMixOfParams: (result: string, isOptionalBoolean?: true) => void;
+  readonly onNoParams: () => void;
+  readonly onVariadicParams: (...args: ReadonlyArray<string>) => void;
+}): void {
+  /* do nothing */
+}
diff --git a/src/hasSubObject.test.ts b/src/hasSubObject.test.ts
new file mode 100644
index 0000000..2cecea9
--- /dev/null
+++ b/src/hasSubObject.test.ts
@@ -0,0 +1,148 @@
+import { hasSubObject } from "./hasSubObject";
+import { pipe } from "./pipe";
+
+describe("data first", () => {
+  test("works with empty sub-object", () => {
+    expect(hasSubObject({ a: 1, b: "b", c: 3 }, {})).toBe(true);
+    expect(hasSubObject({}, {})).toBe(true);
+  });
+
+  test("works with primitives", () => {
+    expect(hasSubObject({ a: 1, b: "b", c: 3 }, { a: 1, b: "b" })).toBe(true);
+    expect(hasSubObject({ a: 1, b: "c", c: 3 }, { a: 1, b: "b" })).toBe(false);
+    expect(hasSubObject({ a: 2, b: "b", c: 3 }, { a: 1, b: "b" })).toBe(false);
+  });
+
+  test("works with deep objects", () => {
+    expect(hasSubObject({ a: { b: 1, c: 2 } }, { a: { b: 1, c: 2 } })).toBe(
+      true,
+    );
+    expect(hasSubObject({ a: { b: 1, c: 2 } }, { a: { b: 1, c: 0 } })).toBe(
+      false,
+    );
+  });
+
+  test("checks for matching key", () => {
+    const data = {} as { a?: undefined };
+    expect(hasSubObject(data, { a: undefined })).toBe(false);
+  });
+});
+
+describe("data last", () => {
+  test("empty sub-object", () => {
+    expect(pipe({ a: 1, b: 2, c: 3 }, hasSubObject({}))).toBe(true);
+    expect(pipe({}, hasSubObject({}))).toBe(true);
+  });
+
+  test("works with primitives", () => {
+    expect(pipe({ a: 1, b: "b", c: 3 }, hasSubObject({ a: 1, b: "b" }))).toBe(
+      true,
+    );
+    expect(pipe({ a: 1, b: "c", c: 3 }, hasSubObject({ a: 1, b: "b" }))).toBe(
+      false,
+    );
+    expect(pipe({ a: 2, b: "b", c: 3 }, hasSubObject({ a: 1, b: "b" }))).toBe(
+      false,
+    );
+  });
+
+  test("works with deep objects", () => {
+    expect(
+      pipe({ a: { b: 1, c: 2 } }, hasSubObject({ a: { b: 1, c: 2 } })),
+    ).toBe(true);
+
+    expect(
+      pipe({ a: { b: 1, c: 2 } }, hasSubObject({ a: { b: 1, c: 3 } })),
+    ).toBe(false);
+  });
+});
+
+describe("typing", () => {
+  describe("data-first", () => {
+    test("must have matching keys and values", () => {
+      expectTypeOf(hasSubObject({ a: 2 }, { a: 1 })).toEqualTypeOf<boolean>();
+
+      // @ts-expect-error [ts2353] - missing a key
+      hasSubObject({ b: 2 }, { a: 1 });
+
+      // @ts-expect-error [ts2322] - different value type
+      hasSubObject({ a: "a" }, { a: 1 });
+
+      // ok - wider value type
+      hasSubObject({ a: "a" } as { a: number | string }, { a: 1 });
+
+      // @ts-expect-error [ts2345] - narrower value type
+      hasSubObject({ a: "a" }, { a: 1 } as { a: number | string });
+
+      // ok - unknown data type
+      hasSubObject({ a: 2 } as unknown, { a: 1 });
+
+      // ok - const value
+      hasSubObject({ a: 2 }, { a: 1 } as const);
+    });
+
+    test("allows nested objects", () => {
+      // ok - nested object has extra keys
+      hasSubObject({ a: { b: 4 } }, { a: { b: 1, c: 2 } });
+
+      // @ts-expect-error [ts2741] - nested object has missing keys
+      hasSubObject({ a: { b: 1, c: 2 } }, { a: { b: 1 } });
+
+      // @ts-expect-error [ts2322] - nested object has wrong value types
+      hasSubObject({ a: { b: 4, c: "c" } }, { a: { b: 1, c: 2 } });
+    });
+
+    test("narrows type", () => {
+      const obj = {} as { a?: string; b?: number };
+
+      if (hasSubObject(obj, {})) {
+        expectTypeOf(obj).toEqualTypeOf<{ a?: string; b?: number }>();
+      }
+
+      if (hasSubObject(obj, { a: "a" })) {
+        expectTypeOf(obj).toEqualTypeOf<{ a: string; b?: number }>();
+      }
+
+      if (hasSubObject(obj, { a: "a" } as const)) {
+        expectTypeOf(obj).toEqualTypeOf<{ a: "a"; b?: number }>();
+      }
+    });
+  });
+
+  describe("data-last", () => {
+    test("must have matching keys and values", () => {
+      expectTypeOf(
+        pipe({ a: 2 }, hasSubObject({ a: 1 })),
+      ).toEqualTypeOf<boolean>();
+
+      // @ts-expect-error [ts2353] - missing a key
+      pipe({ b: 2 }, hasSubObject({ a: 1 }));
+
+      // @ts-expect-error [ts2345] - different value type
+      pipe({ a: "a" }, hasSubObject({ a: 1 }));
+
+      // ok - wider value type
+      pipe({ a: "a" } as { a: number | string }, hasSubObject({ a: 1 }));
+
+      // @ts-expect-error [ts2345] - narrower value type
+      pipe({ a: "a" }, hasSubObject({ a: 1 } as { a: number | string }));
+
+      // ok - unknown data type
+      pipe({ a: 2 } as unknown, hasSubObject({ a: 1 }));
+
+      // ok - const value
+      pipe({ a: 2 }, hasSubObject({ a: 1 } as const));
+    });
+
+    test("allows nested objects", () => {
+      // ok - nested object has extra keys
+      pipe({ a: { b: 4 } }, hasSubObject({ a: { b: 1, c: 2 } }));
+
+      // @ts-expect-error [ts2345] - nested object has missing keys
+      pipe({ a: { b: 1, c: 2 } }, hasSubObject({ a: { b: 1 } }));
+
+      // @ts-expect-error [ts2345] - nested object has wrong value types
+      pipe({ a: { b: 4, c: "c" } }, hasSubObject({ a: { b: 1, c: 2 } }));
+    });
+  });
+});