Repository: remeda/remeda
Pull request #621 (2024-04-08 13:30:41)

fix: "no-dangle-underscore", and other nits.
And follow up with going over new rules and old rules and making sure our config is top-notch.

eranhirsch: This will have to wait for typescript-eslint to also update to v9, in the meantime this PR can't build in CI.
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/621/builds/496825) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 8c037e206af59d5ef43bc359f94456339736078a:

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

eranhirsch: It's taking the community longer than I thought to migrate to eslint v9, and the resulting changes in this PR don't need v9 to work - so we can ship the changes to the config itself later.

This mainly removes the underscore-based private functions in favor of proper names and directories.

Also removes runtime protections from sample which was the only function we had with runtime protections.

Patch:
diff --git a/eslint.config.js b/eslint.config.js
index 984c1d1..51b6c56 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -83,7 +83,6 @@ export default config(
       "arrow-body-style": "warn",
       curly: "error",
       "default-case-last": "warn",
-      "dot-notation": "warn",
       eqeqeq: ["error", "always", { null: "always" }],
       "func-style": ["error", "declaration", { allowArrowFunctions: true }],
       "guard-for-in": "error",
@@ -405,13 +404,10 @@ export default config(
     },
   },
   {
-    files: ["src/_*.ts"],
+    files: ["src/internal/*.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/package-lock.json b/package-lock.json
index bda2df1..59e6efe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1138,9 +1138,9 @@
       }
     },
     "node_modules/@rollup/rollup-android-arm-eabi": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz",
-      "integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.1.tgz",
+      "integrity": "sha512-92/y0TqNLRYOTXpm6Z7mnpvKAG9P7qmK7yJeRJSdzElNCUnsgbpAsGqerUboYRIQKzgfq4pWu9xVkgpWLfmNsw==",
       "cpu": [
         "arm"
       ],
@@ -1151,9 +1151,9 @@
       ]
     },
     "node_modules/@rollup/rollup-android-arm64": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz",
-      "integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.1.tgz",
+      "integrity": "sha512-ttWB6ZCfRLuDIUiE0yiu5gcqOsYjA5F7kEV1ggHMj20FwLZ8A1FMeahZJFl/pnOmcnD2QL0z4AcDuo27utGU8A==",
       "cpu": [
         "arm64"
       ],
@@ -1164,9 +1164,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-arm64": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz",
-      "integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.1.tgz",
+      "integrity": "sha512-QLDvPLetbqjHojTGFw9+nuSP3YY/iz2k1cep6crYlr97sS+ZJ0W43b8Z0zC00+lnFZj6JSNxiA4DjboNQMuh1A==",
       "cpu": [
         "arm64"
       ],
@@ -1177,9 +1177,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-x64": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz",
-      "integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.1.tgz",
+      "integrity": "sha512-TAUK/D8khRrRIa1KwRzo8JNKk3tcqaeXWdtsiLgA8zmACWwlWLjPCJ4DULGHQrMkeBjp1Cd3Yuwx04lZgFx5Vg==",
       "cpu": [
         "x64"
       ],
@@ -1190,9 +1190,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz",
-      "integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.1.tgz",
+      "integrity": "sha512-KO+WGZjrh6zyFTD1alIFkfdtxf8B4BC+hqd3kBZHscPLvE5FR/6QKsyuCT0JlERxxYBSUKNUQ/UHyX5uwO1x2A==",
       "cpu": [
         "arm"
       ],
@@ -1203,9 +1203,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm-musleabihf": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz",
-      "integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.1.tgz",
+      "integrity": "sha512-NqxbllzIB1WoAo4ThUXVtd21iiM5IHMTTXmXySKBLVcZvkU0HIZmatlP7hLzb5yQubcmdIeWmncd2NdsjocEiw==",
       "cpu": [
         "arm"
       ],
@@ -1216,9 +1216,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-gnu": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz",
-      "integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.1.tgz",
+      "integrity": "sha512-snma5NvV8y7IECQ5rq0sr0f3UUu+92NVmG/913JXJMcXo84h9ak9TA5UI9Cl2XRM9j3m37QwDBtEYnJzRkSmxA==",
       "cpu": [
         "arm64"
       ],
@@ -1229,9 +1229,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-musl": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz",
-      "integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.1.tgz",
+      "integrity": "sha512-KOvqGprlD84ueivhCi2flvcUwDRD20mAsE3vxQNVEI2Di9tnPGAfEu6UcrSPZbM+jG2w1oSr43hrPo0RNg6GGg==",
       "cpu": [
         "arm64"
       ],
@@ -1242,9 +1242,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz",
-      "integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.1.tgz",
+      "integrity": "sha512-/gsNwtiGLqYwN4vP+EIdUC6Q6LTlpupWqokqIndvZcjn9ig/5P01WyaYCU2wvfL/2Z82jp5kX8c1mDBOvCP3zg==",
       "cpu": [
         "ppc64"
       ],
@@ -1255,9 +1255,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-riscv64-gnu": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz",
-      "integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.1.tgz",
+      "integrity": "sha512-uU8zuGkQfGqfD9w6VRJZI4IuG4JIfNxxJgEmLMAmPVHREKGsxFVfgHy5c6CexQF2vOfgjB33OsET3Vdn2lln9A==",
       "cpu": [
         "riscv64"
       ],
@@ -1268,9 +1268,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-s390x-gnu": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz",
-      "integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.1.tgz",
+      "integrity": "sha512-lsjLtDgtcGFEuBP6yrXwkRN5/wKlvUZtfbKZZu0yaoNpiBL4epgnO21osAALIspVRnl4qZgyLFd8xjCYYWgwfw==",
       "cpu": [
         "s390x"
       ],
@@ -1281,9 +1281,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-gnu": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz",
-      "integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.1.tgz",
+      "integrity": "sha512-N2ZizKhUryqqrMfdCnjhJhZRgv61C6gK+hwVtCIKC8ts8J+go+vqENnGexwg21nHIOvLN5mBM8a7DI2vlyIOPg==",
       "cpu": [
         "x64"
       ],
@@ -1294,9 +1294,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-musl": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz",
-      "integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.1.tgz",
+      "integrity": "sha512-5ICeMxqg66FrOA2AbnBQ2TJVxfvZsKLxmof0ibvPLaYtbsJqnTUtJOofgWb46Gjd4uZcA4rdsp4JCxegzQPqCg==",
       "cpu": [
         "x64"
       ],
@@ -1307,9 +1307,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-arm64-msvc": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz",
-      "integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.1.tgz",
+      "integrity": "sha512-1vIP6Ce02L+qWD7uZYRiFiuAJo3m9kARatWmFSnss0gZnVj2Id7OPUU9gm49JPGasgcR3xMqiH3fqBJ8t00yVg==",
       "cpu": [
         "arm64"
       ],
@@ -1320,9 +1320,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-ia32-msvc": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz",
-      "integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.1.tgz",
+      "integrity": "sha512-Y3M92DcVsT6LoP+wrKpoUWPaazaP1fzbNkp0a0ZSj5Y//+pQVfVe/tQdsYQQy7dwXR30ZfALUIc9PCh9Izir6w==",
       "cpu": [
         "ia32"
       ],
@@ -1333,9 +1333,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-x64-msvc": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz",
-      "integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.1.tgz",
+      "integrity": "sha512-x0fvpHMuF7fK5r8oZxSi8VYXkrVmRgubXpO/wcf15Lk3xZ4Jvvh5oG+u7Su1776A7XzVKZhD2eRc4t7H50gL3w==",
       "cpu": [
         "x64"
       ],
@@ -1661,9 +1661,9 @@
       }
     },
     "node_modules/@types/eslint": {
-      "version": "8.56.9",
-      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz",
-      "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==",
+      "version": "8.56.10",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
+      "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==",
       "dev": true,
       "dependencies": {
         "@types/estree": "*",
@@ -2493,9 +2493,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001610",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001610.tgz",
-      "integrity": "sha512-QFutAY4NgaelojVMjY63o6XlZyORPaLfyMnsl3HgnWdJUcX6K0oaJymHjH8PT5Gk7sTm8rvC/c5COUQKXqmOMA==",
+      "version": "1.0.30001612",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
+      "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
       "dev": true,
       "funding": [
         {
@@ -2940,6 +2940,12 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
     },
+    "node_modules/confbox": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz",
+      "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==",
+      "dev": true
+    },
     "node_modules/config-chain": {
       "version": "1.1.13",
       "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
@@ -3297,9 +3303,9 @@
       "dev": true
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.738",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.738.tgz",
-      "integrity": "sha512-lwKft2CLFztD+vEIpesrOtCrko/TFnEJlHFdRhazU7Y/jx5qc4cqsocfVrBg4So4gGe9lvxnbLIoev47WMpg+A==",
+      "version": "1.4.745",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz",
+      "integrity": "sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA==",
       "dev": true
     },
     "node_modules/emoji-regex": {
@@ -5200,12 +5206,6 @@
       "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
       "dev": true
     },
-    "node_modules/jsonc-parser": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
-      "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==",
-      "dev": true
-    },
     "node_modules/jsonfile": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -5572,15 +5572,12 @@
       }
     },
     "node_modules/magic-string": {
-      "version": "0.30.9",
-      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz",
-      "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==",
+      "version": "0.30.10",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz",
+      "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==",
       "dev": true,
       "dependencies": {
         "@jridgewell/sourcemap-codec": "^1.4.15"
-      },
-      "engines": {
-        "node": ">=12"
       }
     },
     "node_modules/magicast": {
@@ -9208,14 +9205,14 @@
       }
     },
     "node_modules/pkg-types": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
-      "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.0.tgz",
+      "integrity": "sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==",
       "dev": true,
       "dependencies": {
-        "jsonc-parser": "^3.2.0",
-        "mlly": "^1.2.0",
-        "pathe": "^1.1.0"
+        "confbox": "^0.1.7",
+        "mlly": "^1.6.1",
+        "pathe": "^1.1.2"
       }
     },
     "node_modules/pluralize": {
@@ -9869,9 +9866,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "4.14.3",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz",
-      "integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==",
+      "version": "4.16.1",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.16.1.tgz",
+      "integrity": "sha512-5CaD3MPDlPKfhqzRvWXK96G6ELJfPZNb3LHiZxTHgDdC6jvwfGz2E8nY+9g1ONk4ttHsK1WaFP19Js4PSr1E3g==",
       "dev": true,
       "dependencies": {
         "@types/estree": "1.0.5"
@@ -9884,22 +9881,22 @@
         "npm": ">=8.0.0"
       },
       "optionalDependencies": {
-        "@rollup/rollup-android-arm-eabi": "4.14.3",
-        "@rollup/rollup-android-arm64": "4.14.3",
-        "@rollup/rollup-darwin-arm64": "4.14.3",
-        "@rollup/rollup-darwin-x64": "4.14.3",
-        "@rollup/rollup-linux-arm-gnueabihf": "4.14.3",
-        "@rollup/rollup-linux-arm-musleabihf": "4.14.3",
-        "@rollup/rollup-linux-arm64-gnu": "4.14.3",
-        "@rollup/rollup-linux-arm64-musl": "4.14.3",
-        "@rollup/rollup-linux-powerpc64le-gnu": "4.14.3",
-        "@rollup/rollup-linux-riscv64-gnu": "4.14.3",
-        "@rollup/rollup-linux-s390x-gnu": "4.14.3",
-        "@rollup/rollup-linux-x64-gnu": "4.14.3",
-        "@rollup/rollup-linux-x64-musl": "4.14.3",
-        "@rollup/rollup-win32-arm64-msvc": "4.14.3",
-        "@rollup/rollup-win32-ia32-msvc": "4.14.3",
-        "@rollup/rollup-win32-x64-msvc": "4.14.3",
+        "@rollup/rollup-android-arm-eabi": "4.16.1",
+        "@rollup/rollup-android-arm64": "4.16.1",
+        "@rollup/rollup-darwin-arm64": "4.16.1",
+        "@rollup/rollup-darwin-x64": "4.16.1",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.16.1",
+        "@rollup/rollup-linux-arm-musleabihf": "4.16.1",
+        "@rollup/rollup-linux-arm64-gnu": "4.16.1",
+        "@rollup/rollup-linux-arm64-musl": "4.16.1",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.16.1",
+        "@rollup/rollup-linux-riscv64-gnu": "4.16.1",
+        "@rollup/rollup-linux-s390x-gnu": "4.16.1",
+        "@rollup/rollup-linux-x64-gnu": "4.16.1",
+        "@rollup/rollup-linux-x64-musl": "4.16.1",
+        "@rollup/rollup-win32-arm64-msvc": "4.16.1",
+        "@rollup/rollup-win32-ia32-msvc": "4.16.1",
+        "@rollup/rollup-win32-x64-msvc": "4.16.1",
         "fsevents": "~2.3.2"
       }
     },
@@ -10074,9 +10071,9 @@
       }
     },
     "node_modules/semantic-release/node_modules/marked": {
-      "version": "12.0.1",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.1.tgz",
-      "integrity": "sha512-Y1/V2yafOcOdWQCX0XpAKXzDakPOpn6U0YLxTJs3cww6VxOzZV1BTOOYWLvH3gX38cq+iLwljHHTnMtlDfg01Q==",
+      "version": "12.0.2",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz",
+      "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==",
       "dev": true,
       "bin": {
         "marked": "bin/marked.js"
@@ -10967,9 +10964,9 @@
       }
     },
     "node_modules/tinybench": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.7.0.tgz",
-      "integrity": "sha512-Qgayeb106x2o4hNzNjsZEfFziw8IbKqtbXBjVh7VIZfBxfD5M4gWtpyx5+YTae2gJ6Y6Dz/KLepiv16RFeQWNA==",
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz",
+      "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==",
       "dev": true
     },
     "node_modules/tinypool": {
@@ -11618,9 +11615,9 @@
       }
     },
     "node_modules/vite": {
-      "version": "5.2.9",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.9.tgz",
-      "integrity": "sha512-uOQWfuZBlc6Y3W/DTuQ1Sr+oIXWvqljLvS881SVmAj00d5RdgShLcuXWxseWPd4HXwiYBFW/vXHfKFeqj9uQnw==",
+      "version": "5.2.10",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz",
+      "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==",
       "dev": true,
       "dependencies": {
         "esbuild": "^0.20.1",
diff --git a/src/_binarySearchCutoffIndex.ts b/src/_binarySearchCutoffIndex.ts
deleted file mode 100644
index 5262d65..0000000
--- a/src/_binarySearchCutoffIndex.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-export function _binarySearchCutoffIndex<T>(
-  array: ReadonlyArray<T>,
-  predicate: (value: T, index: number, data: ReadonlyArray<T>) => boolean,
-): number {
-  // !IMPORTANT: This docblock is not above the function because then the code that builds our docs site breaks. Please do not move it.
-  /**
-   * A binary search implementation that finds the index at which `predicate`
-   * stops returning `true` and starts returning `false` (consistently) when run
-   * on the items of the array. It **assumes** that mapping the array via the
-   * predicate results in the shape `[...true[], ...false[]]`. *For any other case
-   * the result is unpredictable*.
-   *
-   * This is the base implementation of the `sortedIndex` functions which define
-   * the predicate for the user, for common use-cases.
-   *
-   * It is similar to `findIndex`, but runs at O(logN), whereas the latter is
-   * general purpose function which runs on any array and predicate, but runs at
-   * O(N) time.
-   */
-
-  let lowIndex = 0;
-  // eslint-disable-next-line @typescript-eslint/prefer-destructuring
-  let highIndex = array.length;
-
-  while (lowIndex < highIndex) {
-    // eslint-disable-next-line no-bitwise -- We use bitwise operator here as a way to find the mid-point and round it down using the same operation.
-    const pivotIndex = (lowIndex + highIndex) >>> 1;
-    const pivot = array[pivotIndex]!;
-
-    if (predicate(pivot, pivotIndex, array)) {
-      lowIndex = pivotIndex + 1;
-    } else {
-      highIndex = pivotIndex;
-    }
-  }
-
-  return highIndex;
-}
diff --git a/src/add.ts b/src/add.ts
index f2e729e..a8c5297 100644
--- a/src/add.ts
+++ b/src/add.ts
@@ -32,9 +32,8 @@ export function add(value: number, addend: number): number;
 export function add(addend: number): (value: number) => number;
 
 export function add(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_add, args);
+  return purry(addImplementation, args);
 }
 
-function _add(value: number, addend: number): number {
-  return value + addend;
-}
+const addImplementation = (value: number, addend: number): number =>
+  value + addend;
diff --git a/src/addProp.ts b/src/addProp.ts
index 71d59b3..9a6692e 100644
--- a/src/addProp.ts
+++ b/src/addProp.ts
@@ -38,16 +38,15 @@ export function addProp<
 >(prop: K, value: V): (obj: T) => T & { [x in K]: V };
 
 export function addProp(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_addProp, args);
+  return purry(addPropImplementation, args);
 }
 
-function _addProp<T extends Record<PropertyKey, unknown>, K extends string, V>(
+const addPropImplementation = <
+  T extends Record<PropertyKey, unknown>,
+  K extends string,
+  V,
+>(
   obj: T,
   prop: K,
   value: V,
-): T & { [x in K]: V } {
-  return {
-    ...obj,
-    [prop]: value,
-  };
-}
+): T & { [x in K]: V } => ({ ...obj, [prop]: value });
diff --git a/src/allPass.ts b/src/allPass.ts
index 5970a5c..a5a24c5 100644
--- a/src/allPass.ts
+++ b/src/allPass.ts
@@ -41,12 +41,10 @@ export function allPass<T>(
 ): (data: T) => boolean;
 
 export function allPass(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_allPass, args);
+  return purry(allPassImplementation, args);
 }
 
-function _allPass<T>(
+const allPassImplementation = <T>(
   data: T,
   fns: ReadonlyArray<(data: T) => boolean>,
-): boolean {
-  return fns.every((fn) => fn(data));
-}
+): boolean => fns.every((fn) => fn(data));
diff --git a/src/anyPass.ts b/src/anyPass.ts
index 130c218..281e1e4 100644
--- a/src/anyPass.ts
+++ b/src/anyPass.ts
@@ -41,12 +41,10 @@ export function anyPass<T>(
 ): (data: T) => boolean;
 
 export function anyPass(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_anyPass, args);
+  return purry(anyPassImplementation, args);
 }
 
-function _anyPass<T>(
+const anyPassImplementation = <T>(
   data: T,
   fns: ReadonlyArray<(data: T) => boolean>,
-): boolean {
-  return fns.some((fn) => fn(data));
-}
+): boolean => fns.some((fn) => fn(data));
diff --git a/src/ceil.ts b/src/ceil.ts
index ecaa004..f252d69 100644
--- a/src/ceil.ts
+++ b/src/ceil.ts
@@ -1,4 +1,4 @@
-import { _withPrecision } from "./_withPrecision";
+import { withPrecision } from "./internal/withPrecision";
 import { purry } from "./purry";
 
 /**
@@ -39,5 +39,5 @@ export function ceil(value: number, precision: number): number;
 export function ceil(precision: number): (value: number) => number;
 
 export function ceil(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_withPrecision(Math.ceil), args);
+  return purry(withPrecision(Math.ceil), args);
 }
diff --git a/src/chunk.ts b/src/chunk.ts
index 9a4a909..17feb1e 100644
--- a/src/chunk.ts
+++ b/src/chunk.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer, NonEmptyArray } from "./_types";
+import type { IterableContainer, NonEmptyArray } from "./internal/types";
 import { purry } from "./purry";
 
 type Chunked<T extends IterableContainer> = T[number] extends never
@@ -44,10 +44,13 @@ export function chunk<T extends IterableContainer>(
 ): (array: T) => Chunked<T>;
 
 export function chunk(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_chunk, args);
+  return purry(chunkImplementation, args);
 }
 
-function _chunk<T>(array: ReadonlyArray<T>, size: number): Array<Array<T>> {
+function chunkImplementation<T>(
+  array: ReadonlyArray<T>,
+  size: number,
+): Array<Array<T>> {
   const ret: Array<Array<T>> = [];
   for (let offset = 0; offset < array.length; offset += size) {
     ret.push(array.slice(offset, offset + size));
diff --git a/src/clamp.ts b/src/clamp.ts
index 0259c54..8e0d149 100644
--- a/src/clamp.ts
+++ b/src/clamp.ts
@@ -37,13 +37,12 @@ export function clamp(value: number, limits: Limits): number;
 export function clamp(limits: Limits): (value: number) => number;
 
 export function clamp(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_clamp, args);
+  return purry(clampImplementation, args);
 }
 
-function _clamp(value: number, { min, max }: Limits): number {
-  return min !== undefined && value < min
+const clampImplementation = (value: number, { min, max }: Limits): number =>
+  min !== undefined && value < min
     ? min
     : max !== undefined && value > max
       ? max
       : value;
-}
diff --git a/src/clone.ts b/src/clone.ts
index 0aa2e04..4dd4d62 100644
--- a/src/clone.ts
+++ b/src/clone.ts
@@ -1,19 +1,25 @@
 /* eslint-disable eqeqeq, guard-for-in, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, @typescript-eslint/prefer-destructuring, @typescript-eslint/prefer-readonly-parameter-types, unicorn/no-null -- FIXME! */
 
-// from https://github.com/ramda/ramda/blob/master/source/internal/_clone.js
-
-function _cloneRegExp(pattern: RegExp): RegExp {
-  return new RegExp(
-    pattern.source,
-    (pattern.global ? "g" : "") +
-      (pattern.ignoreCase ? "i" : "") +
-      (pattern.multiline ? "m" : "") +
-      (pattern.sticky ? "y" : "") +
-      (pattern.unicode ? "u" : ""),
-  );
+/**
+ * Creates a deep copy of the value. Supported types: `Array`, `Object`, `Number`, `String`, `Boolean`, `Date`, `RegExp`. Functions are assigned by reference rather than copied.
+ *
+ * @param value - The object to clone.
+ * @signature R.clone(value)
+ * @example R.clone({foo: 'bar'}) // {foo: 'bar'}
+ * @category Object
+ */
+export function clone<T>(value: T): T {
+  return value != null && typeof (value as any).clone === "function"
+    ? (value as any).clone()
+    : cloneImplementation(value, [], []);
 }
 
-function _clone(value: any, refFrom: Array<any>, refTo: Array<any>): unknown {
+// from https://github.com/ramda/ramda/blob/master/source/internal/_clone.js
+function cloneImplementation(
+  value: any,
+  refFrom: Array<any>,
+  refTo: Array<any>,
+): unknown {
   function copy(copiedValue: any): unknown {
     const len = refFrom.length;
     let idx = 0;
@@ -26,7 +32,7 @@ function _clone(value: any, refFrom: Array<any>, refTo: Array<any>): unknown {
     refFrom[idx + 1] = value;
     refTo[idx + 1] = copiedValue;
     for (const key in value) {
-      copiedValue[key] = _clone(value[key], refFrom, refTo);
+      copiedValue[key] = cloneImplementation(value[key], refFrom, refTo);
     }
     return copiedValue;
   }
@@ -38,30 +44,25 @@ function _clone(value: any, refFrom: Array<any>, refTo: Array<any>): unknown {
     case "Date":
       return new Date(value.valueOf());
     case "RegExp":
-      return _cloneRegExp(value);
+      return cloneRegExp(value);
     default:
       return value;
   }
 }
 
-/**
- * Creates a deep copy of the value. Supported types: `Array`, `Object`, `Number`, `String`, `Boolean`, `Date`, `RegExp`. Functions are assigned by reference rather than copied.
- *
- * @param value - The object to clone.
- * @signature R.clone(value)
- * @example R.clone({foo: 'bar'}) // {foo: 'bar'}
- * @category Object
- */
-export function clone<T>(value: T): T {
-  return value != null && typeof (value as any).clone === "function"
-    ? (value as any).clone()
-    : _clone(value, [], []);
-}
-
-function type(val: unknown): string {
-  return val === null
+const type = (val: unknown): string =>
+  val === null
     ? "Null"
     : val === undefined
       ? "Undefined"
       : Object.prototype.toString.call(val).slice(8, -1);
-}
+
+const cloneRegExp = (pattern: RegExp): RegExp =>
+  new RegExp(
+    pattern.source,
+    (pattern.global ? "g" : "") +
+      (pattern.ignoreCase ? "i" : "") +
+      (pattern.multiline ? "m" : "") +
+      (pattern.sticky ? "y" : "") +
+      (pattern.unicode ? "u" : ""),
+  );
diff --git a/src/concat.ts b/src/concat.ts
index da78b7c..93cd50d 100644
--- a/src/concat.ts
+++ b/src/concat.ts
@@ -1,4 +1,4 @@
-import { type IterableContainer } from "./_types";
+import { type IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/conditional.ts b/src/conditional.ts
index 3e8c62a..48701b5 100644
--- a/src/conditional.ts
+++ b/src/conditional.ts
@@ -1,6 +1,6 @@
 /* eslint-disable jsdoc/check-param-names, jsdoc/require-param -- we don't document the case params, it'd be redundant */
 
-import { purryOn } from "./_purryOn";
+import { purryOn } from "./internal/purryOn";
 
 type Case<In, Out, Thru extends In = In> = readonly [
   when: ((data: In) => boolean) | ((data: In) => data is Thru),
diff --git a/src/difference.ts b/src/difference.ts
index 3828be7..de7ccb3 100644
--- a/src/difference.ts
+++ b/src/difference.ts
@@ -1,5 +1,5 @@
-import { _reduceLazy } from "./_reduceLazy";
-import { lazyIdentityEvaluator } from "./_utilityEvaluators";
+import { reduceLazy } from "./internal/reduceLazy";
+import { lazyIdentityEvaluator } from "./internal/utilityEvaluators";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -50,7 +50,7 @@ export function difference(...args: ReadonlyArray<unknown>): unknown {
 const differenceImplementation = <T>(
   array: ReadonlyArray<T>,
   other: ReadonlyArray<T>,
-): Array<T> => _reduceLazy(array, lazyImplementation(other));
+): Array<T> => reduceLazy(array, lazyImplementation(other));
 
 function lazyImplementation<T>(other: ReadonlyArray<T>): LazyEvaluator<T> {
   if (other.length === 0) {
diff --git a/src/differenceWith.ts b/src/differenceWith.ts
index d18fce3..17d8b84 100644
--- a/src/differenceWith.ts
+++ b/src/differenceWith.ts
@@ -1,4 +1,4 @@
-import { _reduceLazy } from "./_reduceLazy";
+import { reduceLazy } from "./internal/reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -65,7 +65,7 @@ function differenceWithImplementation<TFirst, TSecond>(
   other: ReadonlyArray<TSecond>,
   isEquals: IsEquals<TFirst, TSecond>,
 ): Array<TFirst> {
-  return _reduceLazy(array, lazyImplementation(other, isEquals));
+  return reduceLazy(array, lazyImplementation(other, isEquals));
 }
 
 const lazyImplementation =
diff --git a/src/divide.ts b/src/divide.ts
index 531dcb0..d46da07 100644
--- a/src/divide.ts
+++ b/src/divide.ts
@@ -30,9 +30,8 @@ export function divide(value: number, divisor: number): number;
 export function divide(divisor: number): (value: number) => number;
 
 export function divide(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_divide, args);
+  return purry(divideImplementation, args);
 }
 
-function _divide(value: number, divisor: number): number {
-  return value / divisor;
-}
+const divideImplementation = (value: number, divisor: number): number =>
+  value / divisor;
diff --git a/src/drop.ts b/src/drop.ts
index 7decfc2..43252b1 100644
--- a/src/drop.ts
+++ b/src/drop.ts
@@ -1,4 +1,4 @@
-import { _reduceLazy } from "./_reduceLazy";
+import { reduceLazy } from "./internal/reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -36,7 +36,7 @@ export function drop(...args: ReadonlyArray<unknown>): unknown {
 }
 
 function dropImplementation<T>(array: ReadonlyArray<T>, n: number): Array<T> {
-  return _reduceLazy(array, lazyImplementation(n));
+  return reduceLazy(array, lazyImplementation(n));
 }
 
 function lazyImplementation<T>(n: number): LazyEvaluator<T> {
diff --git a/src/dropFirstBy.ts b/src/dropFirstBy.ts
index 23bd977..73e4fed 100644
--- a/src/dropFirstBy.ts
+++ b/src/dropFirstBy.ts
@@ -1,9 +1,9 @@
-import { heapify, heapMaybeInsert } from "./_heap";
+import { heapify, heapMaybeInsert } from "./internal/heap";
 import {
   purryOrderRulesWithArgument,
   type OrderRule,
-} from "./_purryOrderRules";
-import type { CompareFunction, NonEmptyArray } from "./_types";
+} from "./internal/purryOrderRules";
+import type { CompareFunction, NonEmptyArray } from "./internal/types";
 
 /**
  * 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.
diff --git a/src/dropLast.ts b/src/dropLast.ts
index 137d839..af29973 100644
--- a/src/dropLast.ts
+++ b/src/dropLast.ts
@@ -28,10 +28,13 @@ export function dropLast<T>(array: ReadonlyArray<T>, n: number): Array<T>;
 export function dropLast<T>(n: number): (array: ReadonlyArray<T>) => Array<T>;
 
 export function dropLast(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_dropLast, args);
+  return purry(dropLastImplementation, args);
 }
 
-function _dropLast<T>(array: ReadonlyArray<T>, n: number): Array<T> {
+function dropLastImplementation<T>(
+  array: ReadonlyArray<T>,
+  n: number,
+): Array<T> {
   const copy = [...array];
   if (n > 0) {
     copy.splice(-n);
diff --git a/src/evolve.ts b/src/evolve.ts
index f6b040b..a1dfda4 100644
--- a/src/evolve.ts
+++ b/src/evolve.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 /**
@@ -131,10 +131,10 @@ export function evolve<T extends object, E extends Evolver<T>>(
 ): (object: T) => Evolved<T, E>;
 
 export function evolve(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_evolve, args);
+  return purry(evolveImplementation, args);
 }
 
-function _evolve(data: unknown, evolver: GenericEvolver): unknown {
+function evolveImplementation(data: unknown, evolver: GenericEvolver): unknown {
   if (typeof data !== "object" || data === null) {
     return data;
   }
@@ -146,7 +146,7 @@ function _evolve(data: unknown, evolver: GenericEvolver): unknown {
       out[key] =
         typeof value === "function"
           ? value(out[key])
-          : _evolve(out[key], value);
+          : evolveImplementation(out[key], value);
     }
   }
 
diff --git a/src/find.ts b/src/find.ts
index ba9d543..62b1183 100644
--- a/src/find.ts
+++ b/src/find.ts
@@ -1,4 +1,4 @@
-import { _toSingle } from "./_toSingle";
+import { toSingle } from "./internal/toSingle";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -75,7 +75,7 @@ export function find<T>(
 ): (data: ReadonlyArray<T>) => T | undefined;
 
 export function find(...args: ReadonlyArray<unknown>): unknown {
-  return purry(findImplementation, args, _toSingle(lazyImplementation));
+  return purry(findImplementation, args, toSingle(lazyImplementation));
 }
 
 const findImplementation = <T, S extends T>(
diff --git a/src/findLast.ts b/src/findLast.ts
index 2a55d8a..5f0b47f 100644
--- a/src/findLast.ts
+++ b/src/findLast.ts
@@ -86,5 +86,6 @@ const findLastImplementation = <T, S extends T>(
       return item;
     }
   }
-  return;
+
+  return undefined;
 };
diff --git a/src/first.ts b/src/first.ts
index 1c316b9..c5c2ab2 100644
--- a/src/first.ts
+++ b/src/first.ts
@@ -1,5 +1,5 @@
-import { _toSingle } from "./_toSingle";
-import type { IterableContainer } from "./_types";
+import { toSingle } from "./internal/toSingle";
+import type { IterableContainer } from "./internal/types";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -47,7 +47,7 @@ export function first<T extends IterableContainer>(data: T): First<T>;
 export function first(): <T extends IterableContainer>(data: T) => First<T>;
 
 export function first(...args: ReadonlyArray<unknown>): unknown {
-  return purry(firstImplementation, args, _toSingle(lazyImplementation));
+  return purry(firstImplementation, args, toSingle(lazyImplementation));
 }
 
 const firstImplementation = <T>([item]: ReadonlyArray<T>): T | undefined =>
diff --git a/src/firstBy.ts b/src/firstBy.ts
index 637de60..eaf077e 100644
--- a/src/firstBy.ts
+++ b/src/firstBy.ts
@@ -1,9 +1,9 @@
-import { purryOrderRules, type OrderRule } from "./_purryOrderRules";
+import { purryOrderRules, type OrderRule } from "./internal/purryOrderRules";
 import type {
   CompareFunction,
   IterableContainer,
   NonEmptyArray,
-} from "./_types";
+} from "./internal/types";
 import { hasAtLeast } from "./hasAtLeast";
 
 type FirstBy<T extends IterableContainer> =
diff --git a/src/flat.ts b/src/flat.ts
index a22ae90..4dbd689 100644
--- a/src/flat.ts
+++ b/src/flat.ts
@@ -1,6 +1,6 @@
 import { type IsNumericLiteral } from "type-fest";
-import { lazyDataLastImpl } from "./_lazyDataLastImpl";
-import type { IterableContainer } from "./_types";
+import { lazyDataLastImpl } from "./internal/lazyDataLastImpl";
+import type { IterableContainer } from "./internal/types";
 import type { LazyEvaluator, LazyResult } from "./pipe";
 
 // This is obvious and not likely to change, but it makes reading the code a
diff --git a/src/floor.ts b/src/floor.ts
index 30a5ad3..acd5f9d 100644
--- a/src/floor.ts
+++ b/src/floor.ts
@@ -1,4 +1,4 @@
-import { _withPrecision } from "./_withPrecision";
+import { withPrecision } from "./internal/withPrecision";
 import { purry } from "./purry";
 
 /**
@@ -39,5 +39,5 @@ export function floor(value: number, precision: number): number;
 export function floor(precision: number): (value: number) => number;
 
 export function floor(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_withPrecision(Math.floor), args);
+  return purry(withPrecision(Math.floor), args);
 }
diff --git a/src/forEachObj.ts b/src/forEachObj.ts
index 55b4bba..8fd2e13 100644
--- a/src/forEachObj.ts
+++ b/src/forEachObj.ts
@@ -1,7 +1,7 @@
 import {
   type EnumerableStringKeyOf,
   type EnumerableStringKeyedValueOf,
-} from "./_types";
+} from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/fromEntries.ts b/src/fromEntries.ts
index 2713a5f..327c92b 100644
--- a/src/fromEntries.ts
+++ b/src/fromEntries.ts
@@ -1,5 +1,5 @@
 import type { Simplify } from "type-fest";
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 type Entry<Key extends PropertyKey = PropertyKey, Value = unknown> = readonly [
diff --git a/src/fromKeys.ts b/src/fromKeys.ts
index 2f2e3f5..bf6cdac 100644
--- a/src/fromKeys.ts
+++ b/src/fromKeys.ts
@@ -1,5 +1,5 @@
 import type { Simplify } from "type-fest";
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 // Takes a union of literals and creates a union of records with the value V for
diff --git a/src/groupBy.ts b/src/groupBy.ts
index 6198062..bb33f08 100644
--- a/src/groupBy.ts
+++ b/src/groupBy.ts
@@ -1,4 +1,4 @@
-import type { ExactRecord, NonEmptyArray } from "./_types";
+import type { ExactRecord, NonEmptyArray } from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/hasAtLeast.ts b/src/hasAtLeast.ts
index 0d245f1..6a7d1ba 100644
--- a/src/hasAtLeast.ts
+++ b/src/hasAtLeast.ts
@@ -1,5 +1,5 @@
 import { type IsNumericLiteral } from "type-fest";
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 type ArraySetRequired<
diff --git a/src/hasSubObject.ts b/src/hasSubObject.ts
index 25b1edb..2d89b78 100644
--- a/src/hasSubObject.ts
+++ b/src/hasSubObject.ts
@@ -44,15 +44,15 @@ export function hasSubObject<T, S extends Partial<T>>(
 ): (data: T) => data is Simplify<S & T>;
 
 export function hasSubObject(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_hasSubObject, args);
+  return purry(hasSubObjectImplementation, args);
 }
 
-function _hasSubObject<T, S extends Partial<T>>(
+function hasSubObjectImplementation<T extends object, S extends Partial<T>>(
   data: T,
   subObject: S,
 ): data is Simplify<S & T> {
   for (const [key, value] of Object.entries(subObject)) {
-    if (!Object.prototype.hasOwnProperty.call(data, key)) {
+    if (!Object.hasOwn(data, key)) {
       return false;
     }
 
diff --git a/src/indexBy.ts b/src/indexBy.ts
index 7bc166d..4ab31d2 100644
--- a/src/indexBy.ts
+++ b/src/indexBy.ts
@@ -1,4 +1,4 @@
-import type { ExactRecord } from "./_types";
+import type { ExactRecord } from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/internal/binarySearchCutoffIndex.ts b/src/internal/binarySearchCutoffIndex.ts
new file mode 100644
index 0000000..80ea5ed
--- /dev/null
+++ b/src/internal/binarySearchCutoffIndex.ts
@@ -0,0 +1,36 @@
+/**
+ * A binary search implementation that finds the index at which `predicate`
+ * stops returning `true` and starts returning `false` (consistently) when run
+ * on the items of the array. It **assumes** that mapping the array via the
+ * predicate results in the shape `[...true[], ...false[]]`. *For any other case
+ * the result is unpredictable*.
+ *
+ * This is the base implementation of the `sortedIndex` functions which define
+ * the predicate for the user, for common use-cases.
+ *
+ * It is similar to `findIndex`, but runs at O(logN), whereas the latter is
+ * general purpose function which runs on any array and predicate, but runs at
+ * O(N) time.
+ */
+export function binarySearchCutoffIndex<T>(
+  array: ReadonlyArray<T>,
+  predicate: (value: T, index: number, data: ReadonlyArray<T>) => boolean,
+): number {
+  let lowIndex = 0;
+  // eslint-disable-next-line @typescript-eslint/prefer-destructuring
+  let highIndex = array.length;
+
+  while (lowIndex < highIndex) {
+    // eslint-disable-next-line no-bitwise -- We use bitwise operator here as a way to find the mid-point and round it down using the same operation.
+    const pivotIndex = (lowIndex + highIndex) >>> 1;
+    const pivot = array[pivotIndex]!;
+
+    if (predicate(pivot, pivotIndex, array)) {
+      lowIndex = pivotIndex + 1;
+    } else {
+      highIndex = pivotIndex;
+    }
+  }
+
+  return highIndex;
+}
diff --git a/src/_heap.ts b/src/internal/heap.ts
similarity index 95%
rename from src/_heap.ts
rename to src/internal/heap.ts
index 33ecf8e..6c52c63 100644
--- a/src/_heap.ts
+++ b/src/internal/heap.ts
@@ -2,9 +2,9 @@
  * Heap related utilities.
  */
 
-import { swapInPlace } from "./_swapInPlace";
-import type { CompareFunction } from "./_types";
-import { hasAtLeast } from "./hasAtLeast";
+import { swapInPlace } from "./swapInPlace";
+import type { CompareFunction } from "./types";
+import { hasAtLeast } from "../hasAtLeast";
 
 /**
  * Mutates an array into a "max"-heap based on `compareFn` so that for any `item` in the heap, `compareFn(heap[0], item) > 0`.
diff --git a/src/_lazyDataLastImpl.ts b/src/internal/lazyDataLastImpl.ts
similarity index 94%
rename from src/_lazyDataLastImpl.ts
rename to src/internal/lazyDataLastImpl.ts
index 5bc0c33..5494d32 100644
--- a/src/_lazyDataLastImpl.ts
+++ b/src/internal/lazyDataLastImpl.ts
@@ -1,6 +1,6 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
 
-import type { LazyEvaluator } from "./pipe";
+import type { LazyEvaluator } from "../pipe";
 
 /**
  * Use this helper function to build the data last implementation together with
diff --git a/src/_purryOn.ts b/src/internal/purryOn.ts
similarity index 100%
rename from src/_purryOn.ts
rename to src/internal/purryOn.ts
diff --git a/src/_purryOrderRules.ts b/src/internal/purryOrderRules.ts
similarity index 98%
rename from src/_purryOrderRules.ts
rename to src/internal/purryOrderRules.ts
index d097f5c..2030409 100644
--- a/src/_purryOrderRules.ts
+++ b/src/internal/purryOrderRules.ts
@@ -1,4 +1,4 @@
-import type { CompareFunction, NonEmptyArray } from "./_types";
+import type { CompareFunction, NonEmptyArray } from "./types";
 
 // We define the comparators in a global const so that they are only
 // instantiated once, and so we can couple a label (string) for them that could
diff --git a/src/_quickSelect.ts b/src/internal/quickSelect.ts
similarity index 96%
rename from src/_quickSelect.ts
rename to src/internal/quickSelect.ts
index 0e7c0b9..a1d4c7a 100644
--- a/src/_quickSelect.ts
+++ b/src/internal/quickSelect.ts
@@ -4,8 +4,8 @@
  * @see https://en.wikipedia.org/wiki/Quickselect
  */
 
-import { swapInPlace } from "./_swapInPlace";
-import type { CompareFunction } from "./_types";
+import { swapInPlace } from "./swapInPlace";
+import type { CompareFunction } from "./types";
 
 /**
  * Perform QuickSelect on the given data. Notice that the data would be cloned
diff --git a/src/_reduceLazy.ts b/src/internal/reduceLazy.ts
similarity index 87%
rename from src/_reduceLazy.ts
rename to src/internal/reduceLazy.ts
index df98e0f..2f935f5 100644
--- a/src/_reduceLazy.ts
+++ b/src/internal/reduceLazy.ts
@@ -1,6 +1,6 @@
-import type { LazyEvaluator } from "./pipe";
+import type { LazyEvaluator } from "../pipe";
 
-export function _reduceLazy<T, K>(
+export function reduceLazy<T, K>(
   array: ReadonlyArray<T>,
   lazy: LazyEvaluator<T, K>,
 ): Array<K> {
diff --git a/src/_swapInPlace.ts b/src/internal/swapInPlace.ts
similarity index 100%
rename from src/_swapInPlace.ts
rename to src/internal/swapInPlace.ts
diff --git a/src/_toSingle.ts b/src/internal/toSingle.ts
similarity index 81%
rename from src/_toSingle.ts
rename to src/internal/toSingle.ts
index ac21cc9..70440e4 100644
--- a/src/_toSingle.ts
+++ b/src/internal/toSingle.ts
@@ -1,6 +1,6 @@
 type Single<Func> = Func & { readonly single: true };
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Typescript requires using `any` to infer any kind of function type, `unknown` is not enough.
-export const _toSingle = <Func extends (...args: any) => unknown>(
+export const toSingle = <Func extends (...args: any) => unknown>(
   fn: Func,
 ): Single<Func> => Object.assign(fn, { single: true as const });
diff --git a/src/_types.ts b/src/internal/types.ts
similarity index 100%
rename from src/_types.ts
rename to src/internal/types.ts
diff --git a/src/_utilityEvaluators.ts b/src/internal/utilityEvaluators.ts
similarity index 92%
rename from src/_utilityEvaluators.ts
rename to src/internal/utilityEvaluators.ts
index 8c6e7cb..3606f13 100644
--- a/src/_utilityEvaluators.ts
+++ b/src/internal/utilityEvaluators.ts
@@ -1,4 +1,4 @@
-import type { LazyResult } from "./pipe";
+import type { LazyResult } from "../pipe";
 
 const EMPTY_PIPE = { done: true, hasNext: false } as const;
 
diff --git a/src/_withPrecision.ts b/src/internal/withPrecision.ts
similarity index 92%
rename from src/_withPrecision.ts
rename to src/internal/withPrecision.ts
index 9fbdbc0..0d4e11d 100644
--- a/src/_withPrecision.ts
+++ b/src/internal/withPrecision.ts
@@ -4,7 +4,7 @@
 // for the negative precision limit, too.
 const MAX_PRECISION = 15;
 
-export function _withPrecision(roundingFn: (value: number) => number) {
+export function withPrecision(roundingFn: (value: number) => number) {
   return (value: number, precision: number): number => {
     if (precision === 0) {
       return roundingFn(value);
diff --git a/src/intersection.ts b/src/intersection.ts
index 64b5fc5..2e1b470 100644
--- a/src/intersection.ts
+++ b/src/intersection.ts
@@ -1,5 +1,5 @@
-import { _reduceLazy } from "./_reduceLazy";
-import { lazyEmptyEvaluator } from "./_utilityEvaluators";
+import { reduceLazy } from "./internal/reduceLazy";
+import { lazyEmptyEvaluator } from "./internal/utilityEvaluators";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -50,7 +50,7 @@ export function intersection(...args: ReadonlyArray<unknown>): unknown {
 const intersectionImplementation = <T, S>(
   data: ReadonlyArray<T>,
   other: ReadonlyArray<S>,
-): Array<S & T> => _reduceLazy(data, lazyImplementation(other));
+): Array<S & T> => reduceLazy(data, lazyImplementation(other));
 
 function lazyImplementation<T, S>(
   other: ReadonlyArray<S>,
diff --git a/src/intersectionWith.ts b/src/intersectionWith.ts
index 72334e5..9a7eb13 100644
--- a/src/intersectionWith.ts
+++ b/src/intersectionWith.ts
@@ -1,4 +1,4 @@
-import { _reduceLazy } from "./_reduceLazy";
+import { reduceLazy } from "./internal/reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -69,7 +69,7 @@ const intersectionWithImplementation = <TFirst, TSecond>(
   array: ReadonlyArray<TFirst>,
   other: ReadonlyArray<TSecond>,
   comparator: Comparator<TFirst, TSecond>,
-): Array<TFirst> => _reduceLazy(array, lazyImplementation(other, comparator));
+): Array<TFirst> => reduceLazy(array, lazyImplementation(other, comparator));
 
 const lazyImplementation =
   <TFirst, TSecond>(
diff --git a/src/invert.ts b/src/invert.ts
index 6c908fd..f1944c9 100644
--- a/src/invert.ts
+++ b/src/invert.ts
@@ -39,10 +39,10 @@ export function invert<T extends object>(object: T): Inverted<T>;
 export function invert<T extends object>(): (object: T) => Inverted<T>;
 
 export function invert(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_invert, args);
+  return purry(invertImplementation, args);
 }
 
-function _invert(
+function invertImplementation(
   data: Readonly<Record<PropertyKey, PropertyKey>>,
 ): Record<PropertyKey, PropertyKey> {
   const result: Record<PropertyKey, PropertyKey> = {};
diff --git a/src/isArray.ts b/src/isArray.ts
index 8833b38..c7c0e8a 100644
--- a/src/isArray.ts
+++ b/src/isArray.ts
@@ -1,4 +1,4 @@
-import type { NarrowedTo } from "./_types";
+import type { NarrowedTo } from "./internal/types";
 
 /**
  * A function that checks if the passed parameter is an Array and narrows its type accordingly.
diff --git a/src/isBigInt.ts b/src/isBigInt.ts
index 2aeb77c..a8d51c9 100644
--- a/src/isBigInt.ts
+++ b/src/isBigInt.ts
@@ -1,4 +1,4 @@
-import type { NarrowedTo } from "./_types";
+import type { NarrowedTo } from "./internal/types";
 
 /**
  * A function that checks if the passed parameter is a bigint and narrows its
diff --git a/src/isBoolean.ts b/src/isBoolean.ts
index 778b095..1116e04 100644
--- a/src/isBoolean.ts
+++ b/src/isBoolean.ts
@@ -1,4 +1,4 @@
-import type { NarrowedTo } from "./_types";
+import type { NarrowedTo } from "./internal/types";
 
 /**
  * A function that checks if the passed parameter is a boolean and narrows its type accordingly.
diff --git a/src/isEmpty.ts b/src/isEmpty.ts
index afa692e..b1c3ccc 100644
--- a/src/isEmpty.ts
+++ b/src/isEmpty.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { isArray } from "./isArray";
 import { isObjectType } from "./isObjectType";
 import { isString } from "./isString";
diff --git a/src/isIncludedIn.ts b/src/isIncludedIn.ts
index 1f80167..c92f231 100644
--- a/src/isIncludedIn.ts
+++ b/src/isIncludedIn.ts
@@ -1,5 +1,5 @@
 import { type IsLiteral } from "type-fest";
-import type { IsUnion, IterableContainer } from "./_types";
+import type { IsUnion, IterableContainer } from "./internal/types";
 
 /**
  * A "constant" tuple is a type that has a single runtime value that can fulfil
diff --git a/src/isNumber.ts b/src/isNumber.ts
index e6f8e9c..9ba896b 100644
--- a/src/isNumber.ts
+++ b/src/isNumber.ts
@@ -1,4 +1,4 @@
-import type { NarrowedTo } from "./_types";
+import type { NarrowedTo } from "./internal/types";
 
 /**
  * A function that checks if the passed parameter is a number and narrows its
diff --git a/src/isObjectType.ts b/src/isObjectType.ts
index b9189a0..e93f9dd 100644
--- a/src/isObjectType.ts
+++ b/src/isObjectType.ts
@@ -1,4 +1,4 @@
-import type { NarrowedTo } from "./_types";
+import type { NarrowedTo } from "./internal/types";
 
 /**
  * Checks if the given parameter is of type `"object"` via `typeof`, excluding `null`.
diff --git a/src/isPlainObject.ts b/src/isPlainObject.ts
index 632c0a6..f8148a7 100644
--- a/src/isPlainObject.ts
+++ b/src/isPlainObject.ts
@@ -1,4 +1,4 @@
-import type { NarrowedTo } from "./_types";
+import type { NarrowedTo } from "./internal/types";
 
 /**
  * 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.
diff --git a/src/isString.ts b/src/isString.ts
index b15e425..5869a2a 100644
--- a/src/isString.ts
+++ b/src/isString.ts
@@ -1,4 +1,4 @@
-import type { NarrowedTo } from "./_types";
+import type { NarrowedTo } from "./internal/types";
 
 /**
  * A function that checks if the passed parameter is a string and narrows its type accordingly.
diff --git a/src/isSymbol.ts b/src/isSymbol.ts
index 55957d4..7f7961d 100644
--- a/src/isSymbol.ts
+++ b/src/isSymbol.ts
@@ -1,4 +1,4 @@
-import type { NarrowedTo } from "./_types";
+import type { NarrowedTo } from "./internal/types";
 
 /**
  * A function that checks if the passed parameter is a symbol and narrows its type accordingly.
diff --git a/src/join.ts b/src/join.ts
index 236a91b..6128802 100644
--- a/src/join.ts
+++ b/src/join.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 type Joinable = bigint | boolean | number | string | null | undefined;
diff --git a/src/keys.ts b/src/keys.ts
index 0869582..ff6024b 100644
--- a/src/keys.ts
+++ b/src/keys.ts
@@ -1,4 +1,7 @@
-import type { EnumerableStringKeyOf, IterableContainer } from "./_types";
+import type {
+  EnumerableStringKeyOf,
+  IterableContainer,
+} from "./internal/types";
 import { purry } from "./purry";
 
 type Keys<T> = T extends IterableContainer ? ArrayKeys<T> : ObjectKeys<T>;
diff --git a/src/last.ts b/src/last.ts
index d31ae1d..a5f2132 100644
--- a/src/last.ts
+++ b/src/last.ts
@@ -1,5 +1,5 @@
 import { type LastArrayElement } from "type-fest";
-import type { IterableContainer } from "./_types";
+import { type IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 type Last<T extends IterableContainer> = LastArrayElement<
@@ -45,9 +45,8 @@ export function last<T extends IterableContainer>(data: T): Last<T>;
 export function last(): <T extends IterableContainer>(data: T) => Last<T>;
 
 export function last(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_last, args);
+  return purry(lastImplementation, args);
 }
 
-function _last<T>(array: ReadonlyArray<T>): T | undefined {
-  return array.at(-1);
-}
+const lastImplementation = <T>(array: ReadonlyArray<T>): T | undefined =>
+  array.at(-1);
diff --git a/src/length.ts b/src/length.ts
index d8f5a09..df5ef6d 100644
--- a/src/length.ts
+++ b/src/length.ts
@@ -28,9 +28,8 @@ export function length<T>(items: Enumerable<T>): number;
 export function length<T>(): (items: Enumerable<T>) => number;
 
 export function length(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_length, args);
+  return purry(lengthImplementation, args);
 }
 
-function _length<T>(items: Enumerable<T>): number {
-  return "length" in items ? items.length : [...items].length;
-}
+const lengthImplementation = <T>(items: Enumerable<T>): number =>
+  "length" in items ? items.length : [...items].length;
diff --git a/src/map.ts b/src/map.ts
index b36ae96..c1302bc 100644
--- a/src/map.ts
+++ b/src/map.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer, Mapped } from "./_types";
+import type { IterableContainer, Mapped } from "./internal/types";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
diff --git a/src/mapKeys.ts b/src/mapKeys.ts
index 5870de7..8c3a6bc 100644
--- a/src/mapKeys.ts
+++ b/src/mapKeys.ts
@@ -7,7 +7,7 @@ import type {
   EnumerableStringKeyOf,
   EnumerableStringKeyedValueOf,
   ExactRecord,
-} from "./_types";
+} from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/mapValues.ts b/src/mapValues.ts
index 96bb701..f1b0d46 100644
--- a/src/mapValues.ts
+++ b/src/mapValues.ts
@@ -2,7 +2,7 @@ import { type Simplify } from "type-fest";
 import {
   type EnumerableStringKeyOf,
   type EnumerableStringKeyedValueOf,
-} from "./_types";
+} from "./internal/types";
 import { purry } from "./purry";
 
 type MappedValues<T extends object, Value> = Simplify<{
diff --git a/src/mapWithFeedback.ts b/src/mapWithFeedback.ts
index 4d8ee43..285f6df 100644
--- a/src/mapWithFeedback.ts
+++ b/src/mapWithFeedback.ts
@@ -1,5 +1,5 @@
-import { _reduceLazy } from "./_reduceLazy";
-import type { IterableContainer, Mapped } from "./_types";
+import { reduceLazy } from "./internal/reduceLazy";
+import type { IterableContainer, Mapped } from "./internal/types";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -81,7 +81,7 @@ const mapWithFeedbackImplementation = <T, U>(
     data: ReadonlyArray<T>,
   ) => U,
   initialValue: U,
-): Array<U> => _reduceLazy(data, lazyImplementation(reducer, initialValue));
+): Array<U> => reduceLazy(data, lazyImplementation(reducer, initialValue));
 
 const lazyImplementation = <T, U>(
   reducer: (
diff --git a/src/merge.ts b/src/merge.ts
index 903e28b..beff6ce 100644
--- a/src/merge.ts
+++ b/src/merge.ts
@@ -54,9 +54,10 @@ export function merge<T, Source>(data: T, source: Source): Merge<T, Source>;
 export function merge<Source>(source: Source): <T>(data: T) => Merge<T, Source>;
 
 export function merge(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_merge, args);
+  return purry(mergeImplementation, args);
 }
 
-function _merge<T, Source>(data: T, source: Source): Merge<T, Source> {
-  return { ...data, ...source };
-}
+const mergeImplementation = <T, Source>(
+  data: T,
+  source: Source,
+): Merge<T, Source> => ({ ...data, ...source });
diff --git a/src/multiply.ts b/src/multiply.ts
index 9dab934..3b079ce 100644
--- a/src/multiply.ts
+++ b/src/multiply.ts
@@ -30,9 +30,8 @@ export function multiply(value: number, multiplicand: number): number;
 export function multiply(multiplicand: number): (value: number) => number;
 
 export function multiply(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_multiply, args);
+  return purry(multiplyImplementation, args);
 }
 
-function _multiply(value: number, multiplicand: number): number {
-  return value * multiplicand;
-}
+const multiplyImplementation = (value: number, multiplicand: number): number =>
+  value * multiplicand;
diff --git a/src/nthBy.ts b/src/nthBy.ts
index 60b682f..2839304 100644
--- a/src/nthBy.ts
+++ b/src/nthBy.ts
@@ -1,13 +1,13 @@
 import {
   purryOrderRulesWithArgument,
   type OrderRule,
-} from "./_purryOrderRules";
-import { quickSelect } from "./_quickSelect";
+} from "./internal/purryOrderRules";
+import { quickSelect } from "./internal/quickSelect";
 import type {
   CompareFunction,
   IterableContainer,
   NonEmptyArray,
-} from "./_types";
+} from "./internal/types";
 
 /**
  * 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)*.
diff --git a/src/objOf.ts b/src/objOf.ts
index 0b74dea..77adf9b 100644
--- a/src/objOf.ts
+++ b/src/objOf.ts
@@ -28,10 +28,12 @@ export function objOf<T, K extends string>(
 ): (value: T) => { [x in K]: T };
 
 export function objOf(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_objOf, args);
+  return purry(objOfImplementation, args);
 }
 
-function _objOf<T, K extends string>(value: T, key: K): { [x in K]: T } {
+const objOfImplementation = <T, K extends string>(
+  value: T,
+  key: K,
+): { [x in K]: T } =>
   // @ts-expect-error [ts2322] - I'm not sure how to get the type right here...
-  return { [key]: value };
-}
+  ({ [key]: value });
diff --git a/src/omit.ts b/src/omit.ts
index 4c04100..25ff95d 100644
--- a/src/omit.ts
+++ b/src/omit.ts
@@ -34,10 +34,10 @@ export function omit<T extends object, K extends keyof T>(
 ): Omit<T, K>;
 
 export function omit(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_omit, args);
+  return purry(omitImplementation, args);
 }
 
-function _omit<T extends object, K extends keyof T>(
+function omitImplementation<T extends object, K extends keyof T>(
   data: T,
   propNames: ReadonlyArray<K>,
 ): Omit<T, K> {
diff --git a/src/omitBy.ts b/src/omitBy.ts
index df3e24a..9ec1d46 100644
--- a/src/omitBy.ts
+++ b/src/omitBy.ts
@@ -2,7 +2,7 @@ import { type IfNever, type Simplify } from "type-fest";
 import {
   type EnumerableStringKeyOf,
   type EnumerableStringKeyedValueOf,
-} from "./_types";
+} from "./internal/types";
 import { purry } from "./purry";
 
 // Symbols are not passed to the predicate (because they can't be enumerated
diff --git a/src/only.ts b/src/only.ts
index 1473ad0..78bee86 100644
--- a/src/only.ts
+++ b/src/only.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 type Only<T extends IterableContainer> = T extends
@@ -45,9 +45,8 @@ export function only<T extends IterableContainer>(): (
 ) => Only<T>;
 
 export function only(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_only, args);
+  return purry(onlyImplementation, args);
 }
 
-function _only<T>(array: ReadonlyArray<T>): T | undefined {
-  return array.length === 1 ? array[0] : undefined;
-}
+const onlyImplementation = <T>(array: ReadonlyArray<T>): T | undefined =>
+  array.length === 1 ? array[0] : undefined;
diff --git a/src/pathOr.ts b/src/pathOr.ts
index c7ef4e7..650749d 100644
--- a/src/pathOr.ts
+++ b/src/pathOr.ts
@@ -145,10 +145,10 @@ export function pathOr<
 ): (object: T) => PathValue3<T, A, B, C>;
 
 export function pathOr(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_pathOr, args);
+  return purry(pathOrImplementation, args);
 }
 
-function _pathOr(
+function pathOrImplementation(
   data: unknown,
   path: ReadonlyArray<PropertyKey>,
   defaultValue: unknown,
diff --git a/src/pick.ts b/src/pick.ts
index b693e49..4d604ef 100644
--- a/src/pick.ts
+++ b/src/pick.ts
@@ -31,10 +31,10 @@ export function pick<T extends object, K extends keyof T>(
 ): Pick<T, K>;
 
 export function pick(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_pick, args);
+  return purry(pickImplementation, args);
 }
 
-function _pick<T extends object, K extends keyof T>(
+function pickImplementation<T extends object, K extends keyof T>(
   object: T,
   names: ReadonlyArray<K>,
 ): Pick<T, K> {
diff --git a/src/pickBy.ts b/src/pickBy.ts
index 1649f25..5ea1a87 100644
--- a/src/pickBy.ts
+++ b/src/pickBy.ts
@@ -2,7 +2,7 @@ import { type IfNever, type Simplify } from "type-fest";
 import {
   type EnumerableStringKeyOf,
   type EnumerableStringKeyedValueOf,
-} from "./_types";
+} from "./internal/types";
 import { purry } from "./purry";
 
 // Because pickBy needs to iterate over all entries of the object, only
diff --git a/src/pipe.ts b/src/pipe.ts
index 70b7cc5..3984022 100644
--- a/src/pipe.ts
+++ b/src/pipe.ts
@@ -280,7 +280,7 @@ export function pipe(
     const accumulator: Array<unknown> = [];
 
     for (const value of output) {
-      const shouldExitEarly = _processItem(value, accumulator, lazySequence);
+      const shouldExitEarly = processItem(value, accumulator, lazySequence);
       if (shouldExitEarly) {
         break;
       }
@@ -293,7 +293,7 @@ export function pipe(
   return output;
 }
 
-function _processItem(
+function processItem(
   item: unknown,
   // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types -- Intentionally mutable, we use the accumulator directly to accumulate the results.
   accumulator: Array<unknown>,
@@ -317,7 +317,7 @@ function _processItem(
     if (lazyResult.hasNext) {
       if (lazyResult.hasMany ?? false) {
         for (const subItem of lazyResult.next as ReadonlyArray<unknown>) {
-          const subResult = _processItem(
+          const subResult = processItem(
             subItem,
             accumulator,
             lazySequence.slice(operationsIndex + 1),
diff --git a/src/product.ts b/src/product.ts
index 8095367..3f085f6 100644
--- a/src/product.ts
+++ b/src/product.ts
@@ -1,4 +1,4 @@
-import { type NonEmptyArray } from "./_types";
+import { type NonEmptyArray } from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/pullObject.ts b/src/pullObject.ts
index 2398569..e105e9f 100644
--- a/src/pullObject.ts
+++ b/src/pullObject.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/purry.ts b/src/purry.ts
index 51161bf..c9b958b 100644
--- a/src/purry.ts
+++ b/src/purry.ts
@@ -1,6 +1,6 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
 
-import { lazyDataLastImpl } from "./_lazyDataLastImpl";
+import { lazyDataLastImpl } from "./internal/lazyDataLastImpl";
 import type { LazyEvaluator } from "./pipe";
 
 /**
diff --git a/src/range.ts b/src/range.ts
index 52aae7b..45ada0b 100644
--- a/src/range.ts
+++ b/src/range.ts
@@ -26,10 +26,10 @@ export function range(start: number, end: number): Array<number>;
 export function range(end: number): (start: number) => Array<number>;
 
 export function range(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_range, args);
+  return purry(rangeImplementation, args);
 }
 
-function _range(start: number, end: number): Array<number> {
+function rangeImplementation(start: number, end: number): Array<number> {
   const ret: Array<number> = [];
   for (let i = start; i < end; i++) {
     ret.push(i);
diff --git a/src/rankBy.ts b/src/rankBy.ts
index 6dbe4ff..8a1782e 100644
--- a/src/rankBy.ts
+++ b/src/rankBy.ts
@@ -1,8 +1,8 @@
 import {
   purryOrderRulesWithArgument,
   type OrderRule,
-} from "./_purryOrderRules";
-import type { CompareFunction, NonEmptyArray } from "./_types";
+} from "./internal/purryOrderRules";
+import type { CompareFunction, NonEmptyArray } from "./internal/types";
 
 /**
  * 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)`.
diff --git a/src/round.ts b/src/round.ts
index 40347c6..3878308 100644
--- a/src/round.ts
+++ b/src/round.ts
@@ -1,4 +1,4 @@
-import { _withPrecision } from "./_withPrecision";
+import { withPrecision } from "./internal/withPrecision";
 import { purry } from "./purry";
 
 /**
@@ -39,5 +39,5 @@ export function round(value: number, precision: number): number;
 export function round(precision: number): (value: number) => number;
 
 export function round(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_withPrecision(Math.round), args);
+  return purry(withPrecision(Math.round), args);
 }
diff --git a/src/sample.ts b/src/sample.ts
index cef8ce6..bb198f1 100644
--- a/src/sample.ts
+++ b/src/sample.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 type Sampled<T extends IterableContainer, N extends number> =
@@ -106,12 +106,9 @@ function sampleImplementation<T>(
   data: ReadonlyArray<T>,
   sampleSize: number,
 ): Array<T> {
-  if (sampleSize < 0) {
-    throw new RangeError(`sampleSize must cannot be negative: ${sampleSize}`);
-  }
-
-  if (!Number.isInteger(sampleSize)) {
-    throw new TypeError(`sampleSize must be an integer: ${sampleSize}`);
+  if (sampleSize <= 0) {
+    // Trivial
+    return [];
   }
 
   if (sampleSize >= data.length) {
@@ -119,11 +116,6 @@ function sampleImplementation<T>(
     return [...data];
   }
 
-  if (sampleSize === 0) {
-    // Trivial
-    return [];
-  }
-
   // We have 2 modes of sampling, depending on the size of the sample requested.
   // 1. If sampleSize is _small_, we generate indices that we then use to
   // *EXTRACT* individual elements from the array.
diff --git a/src/set.ts b/src/set.ts
index 929f921..7d8f77e 100644
--- a/src/set.ts
+++ b/src/set.ts
@@ -30,12 +30,11 @@ export function set<T, K extends keyof T>(obj: T, prop: K, value: T[K]): T;
 export function set<T, K extends keyof T>(prop: K, value: T[K]): (obj: T) => T;
 
 export function set(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_set, args);
+  return purry(setImplementation, args);
 }
 
-function _set<T, K extends keyof T>(obj: T, prop: K, value: T[K]): T {
-  return {
-    ...obj,
-    [prop]: value,
-  };
-}
+const setImplementation = <T, K extends keyof T>(
+  obj: T,
+  prop: K,
+  value: T[K],
+): T => ({ ...obj, [prop]: value });
diff --git a/src/shuffle.ts b/src/shuffle.ts
index 59a6ab0..a085610 100644
--- a/src/shuffle.ts
+++ b/src/shuffle.ts
@@ -26,10 +26,10 @@ export function shuffle<T>(items: ReadonlyArray<T>): Array<T>;
 export function shuffle<T>(): (items: ReadonlyArray<T>) => Array<T>;
 
 export function shuffle(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_shuffle, args);
+  return purry(shuffleImplementation, args);
 }
 
-function _shuffle<T>(items: ReadonlyArray<T>): Array<T> {
+function shuffleImplementation<T>(items: ReadonlyArray<T>): Array<T> {
   const result = [...items];
   for (let index = 0; index < items.length; index++) {
     const rand = index + Math.floor(Math.random() * (items.length - index));
diff --git a/src/sort.ts b/src/sort.ts
index af6aa2f..ab721e8 100644
--- a/src/sort.ts
+++ b/src/sort.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer, ReorderedArray } from "./_types";
+import type { IterableContainer, ReorderedArray } from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/sortBy.ts b/src/sortBy.ts
index 09c7d4d..dc4cb90 100644
--- a/src/sortBy.ts
+++ b/src/sortBy.ts
@@ -1,10 +1,10 @@
-import { purryOrderRules, type OrderRule } from "./_purryOrderRules";
+import { purryOrderRules, type OrderRule } from "./internal/purryOrderRules";
 import type {
   CompareFunction,
   IterableContainer,
   NonEmptyArray,
   ReorderedArray,
-} from "./_types";
+} from "./internal/types";
 
 /**
  * Sorts `data` using the provided ordering rules. The `sort` is done via the
diff --git a/src/sortedIndex.ts b/src/sortedIndex.ts
index 341d696..59bdf8d 100644
--- a/src/sortedIndex.ts
+++ b/src/sortedIndex.ts
@@ -1,5 +1,5 @@
 import { purry } from "./purry";
-import { _binarySearchCutoffIndex } from "./_binarySearchCutoffIndex";
+import { binarySearchCutoffIndex } from "./internal/binarySearchCutoffIndex";
 
 /**
  * Find the insertion position (index) of an item in an array with items sorted
@@ -51,4 +51,4 @@ export function sortedIndex(...args: ReadonlyArray<unknown>): unknown {
 const sortedIndexImplementation = <T>(
   array: ReadonlyArray<T>,
   item: T,
-): number => _binarySearchCutoffIndex(array, (pivot) => pivot < item);
+): number => binarySearchCutoffIndex(array, (pivot) => pivot < item);
diff --git a/src/sortedIndexBy.ts b/src/sortedIndexBy.ts
index 20c9766..4457f59 100644
--- a/src/sortedIndexBy.ts
+++ b/src/sortedIndexBy.ts
@@ -1,5 +1,5 @@
 import { purry } from "./purry";
-import { _binarySearchCutoffIndex } from "./_binarySearchCutoffIndex";
+import { binarySearchCutoffIndex } from "./internal/binarySearchCutoffIndex";
 
 /**
  * Find the insertion position (index) of an item in an array with items sorted
@@ -98,7 +98,7 @@ function sortedIndexByImplementation<T>(
   ) => NonNullable<unknown>,
 ): number {
   const value = valueFunction(item, undefined /* index */, data);
-  return _binarySearchCutoffIndex(
+  return binarySearchCutoffIndex(
     data,
     (pivot, index) => valueFunction(pivot, index, data) < value,
   );
diff --git a/src/sortedIndexWith.ts b/src/sortedIndexWith.ts
index 742130c..7233f38 100644
--- a/src/sortedIndexWith.ts
+++ b/src/sortedIndexWith.ts
@@ -1,5 +1,5 @@
 import { purry } from "./purry";
-import { _binarySearchCutoffIndex } from "./_binarySearchCutoffIndex";
+import { binarySearchCutoffIndex } from "./internal/binarySearchCutoffIndex";
 
 /**
  * Performs a **binary search** for the index of the item at which the predicate
@@ -77,5 +77,5 @@ export function sortedIndexWith<T>(
 ): (data: ReadonlyArray<T>) => number;
 
 export function sortedIndexWith(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_binarySearchCutoffIndex, args);
+  return purry(binarySearchCutoffIndex, args);
 }
diff --git a/src/sortedLastIndex.ts b/src/sortedLastIndex.ts
index 96fa523..425e35f 100644
--- a/src/sortedLastIndex.ts
+++ b/src/sortedLastIndex.ts
@@ -1,5 +1,5 @@
 import { purry } from "./purry";
-import { _binarySearchCutoffIndex } from "./_binarySearchCutoffIndex";
+import { binarySearchCutoffIndex } from "./internal/binarySearchCutoffIndex";
 
 /**
  * Find the insertion position (index) of an item in an array with items sorted
@@ -52,7 +52,7 @@ const sortedLastIndexImplementation = <T>(
   array: ReadonlyArray<T>,
   item: T,
 ): number =>
-  _binarySearchCutoffIndex(
+  binarySearchCutoffIndex(
     array,
     // The only difference between the regular implementation and the "last"
     // variation is that we consider the pivot with equality too, so that we
diff --git a/src/sortedLastIndexBy.ts b/src/sortedLastIndexBy.ts
index 3eebe6d..3d2b7f3 100644
--- a/src/sortedLastIndexBy.ts
+++ b/src/sortedLastIndexBy.ts
@@ -1,5 +1,5 @@
 import { purry } from "./purry";
-import { _binarySearchCutoffIndex } from "./_binarySearchCutoffIndex";
+import { binarySearchCutoffIndex } from "./internal/binarySearchCutoffIndex";
 
 /**
  * Find the insertion position (index) of an item in an array with items sorted
@@ -100,7 +100,7 @@ function sortedLastIndexByImplementation<T>(
   ) => NonNullable<unknown>,
 ): number {
   const value = valueFunction(item, undefined /* index */, array);
-  return _binarySearchCutoffIndex(
+  return binarySearchCutoffIndex(
     array,
     // The only difference between the regular implementation and the "last"
     // variation is that we consider the pivot with equality too, so that we
diff --git a/src/splice.ts b/src/splice.ts
index af7561a..96d0d8d 100644
--- a/src/splice.ts
+++ b/src/splice.ts
@@ -43,10 +43,10 @@ export function splice<T>(
 ): (items: ReadonlyArray<T>) => Array<T>;
 
 export function splice(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_splice, args);
+  return purry(spliceImplementation, args);
 }
 
-function _splice<T>(
+function spliceImplementation<T>(
   items: ReadonlyArray<T>,
   start: number,
   deleteCount: number,
diff --git a/src/splitAt.ts b/src/splitAt.ts
index 821d9f9..05040ec 100644
--- a/src/splitAt.ts
+++ b/src/splitAt.ts
@@ -35,10 +35,10 @@ export function splitAt<T>(
 ): (array: ReadonlyArray<T>) => [Array<T>, Array<T>];
 
 export function splitAt(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_splitAt, args);
+  return purry(splitAtImplementation, args);
 }
 
-function _splitAt<T>(
+function splitAtImplementation<T>(
   array: ReadonlyArray<T>,
   index: number,
 ): [Array<T>, Array<T>] {
diff --git a/src/stringToPath.ts b/src/stringToPath.ts
index 788c8f1..5522802 100644
--- a/src/stringToPath.ts
+++ b/src/stringToPath.ts
@@ -1,5 +1,3 @@
-/* eslint-disable dot-notation -- This rule is turned off in PR #621 */
-
 const PATH_RE = /^(?:\.?(?<propName>[^.[\]]+)|\[(?<index>.+?)\])(?<rest>.*)$/u;
 
 type StringToPath<T extends string> = string extends T
@@ -27,7 +25,7 @@ type StringToPath<T extends string> = string extends T
  * @signature R.stringToPathArray(path)
  * @example R.stringToPathArray('a.b[0].c') // => ['a', 'b', '0', 'c']
  * @dataFirst
- * @category String
+ * @category Utility
  */
 export function stringToPath<Path extends string>(
   path: Path,
@@ -38,11 +36,11 @@ export function stringToPath<Path extends string>(
 
   const match = PATH_RE.exec(path);
   return (
-    match === null
+    match?.groups === undefined
       ? [path]
       : [
-          match.groups!["index"] ?? match.groups!["propName"]!,
-          ...stringToPath(match.groups!["rest"]!),
+          match.groups["index"] ?? match.groups["propName"]!,
+          ...stringToPath(match.groups["rest"]!),
         ]
   ) as StringToPath<Path>;
 }
diff --git a/src/subtract.ts b/src/subtract.ts
index 7a4b044..1d1bd10 100644
--- a/src/subtract.ts
+++ b/src/subtract.ts
@@ -32,9 +32,8 @@ export function subtract(value: number, subtrahend: number): number;
 export function subtract(subtrahend: number): (value: number) => number;
 
 export function subtract(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_subtract, args);
+  return purry(subtractImplementation, args);
 }
 
-function _subtract(value: number, subtrahend: number): number {
-  return value - subtrahend;
-}
+const subtractImplementation = (value: number, subtrahend: number): number =>
+  value - subtrahend;
diff --git a/src/sum.ts b/src/sum.ts
index 231bc0a..3b62b1f 100644
--- a/src/sum.ts
+++ b/src/sum.ts
@@ -1,4 +1,4 @@
-import { type NonEmptyArray } from "./_types";
+import { type NonEmptyArray } from "./internal/types";
 import { purry } from "./purry";
 
 /**
diff --git a/src/swapIndices.ts b/src/swapIndices.ts
index 99c4c5b..d7a42dc 100644
--- a/src/swapIndices.ts
+++ b/src/swapIndices.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import type { Joined } from "./join";
 import { purry } from "./purry";
 
@@ -153,48 +153,42 @@ export function swapIndices<K1 extends number, K2 extends number>(
 ): <T extends IterableContainer | string>(data: T) => SwappedIndices<T, K1, K2>;
 
 export function swapIndices(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_swapIndices, args);
+  return purry(swapIndicesImplementation, args);
 }
 
-function _swapIndices(
-  item: IterableContainer | string,
+const swapIndicesImplementation = (
+  data: IterableContainer | string,
   index1: number,
   index2: number,
-): unknown {
-  return typeof item === "string"
-    ? _swapString(item, index1, index2)
-    : _swapArray(item, index1, index2);
-}
+): unknown =>
+  typeof data === "string"
+    ? swapArray([...data], index1, index2).join("")
+    : swapArray(data, index1, index2);
 
-function _swapArray(
-  item: ReadonlyArray<unknown>,
+function swapArray(
+  data: ReadonlyArray<unknown>,
   index1: number,
   index2: number,
 ): Array<unknown> {
-  const result = [...item];
+  const result = [...data];
 
   if (Number.isNaN(index1) || Number.isNaN(index2)) {
     return result;
   }
 
-  const positiveIndexA = index1 < 0 ? item.length + index1 : index1;
-  const positiveIndexB = index2 < 0 ? item.length + index2 : index2;
+  const positiveIndexA = index1 < 0 ? data.length + index1 : index1;
+  const positiveIndexB = index2 < 0 ? data.length + index2 : index2;
 
-  if (positiveIndexA < 0 || positiveIndexA > item.length) {
+  if (positiveIndexA < 0 || positiveIndexA > data.length) {
     return result;
   }
 
-  if (positiveIndexB < 0 || positiveIndexB > item.length) {
+  if (positiveIndexB < 0 || positiveIndexB > data.length) {
     return result;
   }
 
-  result[positiveIndexA] = item[positiveIndexB];
-  result[positiveIndexB] = item[positiveIndexA];
+  result[positiveIndexA] = data[positiveIndexB];
+  result[positiveIndexB] = data[positiveIndexA];
 
   return result;
 }
-
-function _swapString(item: string, index1: number, index2: number): string {
-  const result = _swapArray([...item], index1, index2);
-  return result.join("");
-}
diff --git a/src/swapProps.ts b/src/swapProps.ts
index a9f8dc3..932deed 100644
--- a/src/swapProps.ts
+++ b/src/swapProps.ts
@@ -44,10 +44,14 @@ export function swapProps<
 >(key1: K1, key2: K2): (data: T) => SwappedProps<T, K1, K2>;
 
 export function swapProps(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_swapProps, args);
+  return purry(swapPropsImplementation, args);
 }
 
-function _swapProps<T extends object, K1 extends keyof T, K2 extends keyof T>(
+function swapPropsImplementation<
+  T extends object,
+  K1 extends keyof T,
+  K2 extends keyof T,
+>(
   obj: T,
   key1: K1,
   key2: K2,
diff --git a/src/take.ts b/src/take.ts
index 61095f8..e70935c 100644
--- a/src/take.ts
+++ b/src/take.ts
@@ -1,4 +1,4 @@
-import { _reduceLazy } from "./_reduceLazy";
+import { reduceLazy } from "./internal/reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -36,7 +36,7 @@ export function take(...args: ReadonlyArray<unknown>): unknown {
 }
 
 const takeImplementation = <T>(array: ReadonlyArray<T>, n: number): Array<T> =>
-  _reduceLazy(array, lazyImplementation(n));
+  reduceLazy(array, lazyImplementation(n));
 
 function lazyImplementation<T>(n: number): LazyEvaluator<T> {
   if (n <= 0) {
diff --git a/src/takeFirstBy.ts b/src/takeFirstBy.ts
index e0f4200..be7ed4d 100644
--- a/src/takeFirstBy.ts
+++ b/src/takeFirstBy.ts
@@ -1,9 +1,9 @@
-import { heapify, heapMaybeInsert } from "./_heap";
+import { heapify, heapMaybeInsert } from "./internal/heap";
 import {
   purryOrderRulesWithArgument,
   type OrderRule,
-} from "./_purryOrderRules";
-import type { CompareFunction, NonEmptyArray } from "./_types";
+} from "./internal/purryOrderRules";
+import type { CompareFunction, NonEmptyArray } from "./internal/types";
 
 /**
  * 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.
diff --git a/src/tap.ts b/src/tap.ts
index 5cc5695..7329e40 100644
--- a/src/tap.ts
+++ b/src/tap.ts
@@ -41,10 +41,10 @@ export function tap<T>(value: T, fn: (value: T) => void): T;
 export function tap<T, F extends (value: T) => unknown>(fn: F): (value: T) => T;
 
 export function tap(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_tap, args);
+  return purry(tapImplementation, args);
 }
 
-function _tap<T>(value: T, fn: (value: T) => void): T {
+function tapImplementation<T>(value: T, fn: (value: T) => void): T {
   fn(value);
   return value;
 }
diff --git a/src/times.ts b/src/times.ts
index a4d70ab..194ab91 100644
--- a/src/times.ts
+++ b/src/times.ts
@@ -30,10 +30,10 @@ export function times<T>(count: number, fn: (n: number) => T): Array<T>;
 export function times<T>(fn: (n: number) => T): (count: number) => Array<T>;
 
 export function times(...args: ReadonlyArray<unknown>): unknown {
-  return purry(_times, args);
+  return purry(timesImplementation, args);
 }
 
-function _times<T>(count: number, fn: (n: number) => T): Array<T> {
+function timesImplementation<T>(count: number, fn: (n: number) => T): Array<T> {
   if (count < 0) {
     throw new RangeError("n must be a non-negative number");
   }
diff --git a/src/unique.ts b/src/unique.ts
index a4da164..4e389ee 100644
--- a/src/unique.ts
+++ b/src/unique.ts
@@ -1,4 +1,4 @@
-import { _reduceLazy } from "./_reduceLazy";
+import { reduceLazy } from "./internal/reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -40,7 +40,7 @@ export function unique(...args: ReadonlyArray<unknown>): unknown {
 }
 
 const uniqueImplementation = <T>(array: ReadonlyArray<T>): Array<T> =>
-  _reduceLazy(array, lazyImplementation());
+  reduceLazy(array, lazyImplementation());
 
 function lazyImplementation<T>(): LazyEvaluator<T> {
   const set = new Set<T>();
diff --git a/src/uniqueBy.ts b/src/uniqueBy.ts
index b3f43a7..75d12f6 100644
--- a/src/uniqueBy.ts
+++ b/src/uniqueBy.ts
@@ -1,4 +1,4 @@
-import { _reduceLazy } from "./_reduceLazy";
+import { reduceLazy } from "./internal/reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -52,7 +52,7 @@ export function uniqueBy(...args: ReadonlyArray<unknown>): unknown {
 const uniqueByImplementation = <T, K>(
   data: ReadonlyArray<T>,
   keyFunction: (item: T, index: number, data: ReadonlyArray<T>) => K,
-): Array<T> => _reduceLazy(data, lazyImplementation(keyFunction));
+): Array<T> => reduceLazy(data, lazyImplementation(keyFunction));
 
 function lazyImplementation<T, K>(
   keyFunction: (item: T, index: number, data: ReadonlyArray<T>) => K,
diff --git a/src/uniqueWith.ts b/src/uniqueWith.ts
index 5124d06..7ddc4fb 100644
--- a/src/uniqueWith.ts
+++ b/src/uniqueWith.ts
@@ -1,4 +1,4 @@
-import { _reduceLazy } from "./_reduceLazy";
+import { reduceLazy } from "./internal/reduceLazy";
 import type { LazyEvaluator } from "./pipe";
 import { purry } from "./purry";
 
@@ -54,7 +54,7 @@ export function uniqueWith(...args: ReadonlyArray<unknown>): unknown {
 const uniqueWithImplementation = <T>(
   data: ReadonlyArray<T>,
   isEquals: IsEquals<T>,
-): Array<T> => _reduceLazy(data, lazyImplementation(isEquals));
+): Array<T> => reduceLazy(data, lazyImplementation(isEquals));
 
 const lazyImplementation =
   <T>(isEquals: IsEquals<T>): LazyEvaluator<T> =>
diff --git a/src/values.ts b/src/values.ts
index 406f745..d687f26 100644
--- a/src/values.ts
+++ b/src/values.ts
@@ -1,7 +1,7 @@
 import {
   type EnumerableStringKeyedValueOf,
   type IterableContainer,
-} from "./_types";
+} from "./internal/types";
 import { purry } from "./purry";
 
 type Values<T extends object> = T extends IterableContainer
diff --git a/src/zip.ts b/src/zip.ts
index d894120..5c20e03 100644
--- a/src/zip.ts
+++ b/src/zip.ts
@@ -1,4 +1,4 @@
-import type { IterableContainer } from "./_types";
+import type { IterableContainer } from "./internal/types";
 import { purry } from "./purry";
 
 type Zipped<Left extends IterableContainer, Right extends IterableContainer> =
diff --git a/tsup.config.ts b/tsup.config.ts
index b871d9c..7dfa140 100644
--- a/tsup.config.ts
+++ b/tsup.config.ts
@@ -39,10 +39,7 @@ async function getEntries(sourceDirectory: string): Promise<Array<string>> {
   const files = await ts.readdir(sourceDirectory);
   return files
     .filter(
-      (fileName) =>
-        fileName.endsWith(".ts") &&
-        !fileName.startsWith("_") &&
-        !fileName.endsWith(".test.ts"),
+      (fileName) => fileName.endsWith(".ts") && !fileName.endsWith(".test.ts"),
     )
     .map((fileName) => path.join(sourceDirectory, fileName));
 }


Test patch:
diff --git a/src/chunk.test.ts b/src/chunk.test.ts
index 0506925..278d77b 100644
--- a/src/chunk.test.ts
+++ b/src/chunk.test.ts
@@ -1,5 +1,5 @@
 import { chunk } from "./chunk";
-import type { NonEmptyArray } from "./_types";
+import type { NonEmptyArray } from "./internal/types";
 
 describe("data first", () => {
   test("equal size", () => {
diff --git a/src/first.test.ts b/src/first.test.ts
index cf9c7b5..895e1aa 100644
--- a/src/first.test.ts
+++ b/src/first.test.ts
@@ -4,9 +4,7 @@ import { first } from "./first";
 import { pipe } from "./pipe";
 
 function defaultTo<T>(d: T) {
-  return function (v: T | null | undefined) {
-    return v ?? d;
-  };
+  return (v: T | null | undefined) => v ?? d;
 }
 
 test("should return first", () => {
diff --git a/src/firstBy.test.ts b/src/firstBy.test.ts
index ae0aa42..e1a9f6d 100644
--- a/src/firstBy.test.ts
+++ b/src/firstBy.test.ts
@@ -1,4 +1,4 @@
-import type { NonEmptyArray } from "./_types";
+import type { NonEmptyArray } from "./internal/types";
 import { firstBy } from "./firstBy";
 import { identity } from "./identity";
 import { pipe } from "./pipe";
diff --git a/src/flat.test.ts b/src/flat.test.ts
index ef7d01e..0d8be68 100644
--- a/src/flat.test.ts
+++ b/src/flat.test.ts
@@ -1,5 +1,5 @@
 import { createLazyInvocationCounter } from "../test/lazyInvocationCounter.js";
-import type { NonEmptyArray } from "./_types";
+import type { NonEmptyArray } from "./internal/types.js";
 import { find } from "./find";
 import { flat } from "./flat";
 import { identity } from "./identity";
diff --git a/src/groupBy.test.ts b/src/groupBy.test.ts
index 94a80f9..969f79a 100644
--- a/src/groupBy.test.ts
+++ b/src/groupBy.test.ts
@@ -1,4 +1,4 @@
-import type { NonEmptyArray } from "./_types";
+import type { NonEmptyArray } from "./internal/types";
 import { groupBy } from "./groupBy";
 import { pipe } from "./pipe";
 import { prop } from "./prop";
diff --git a/src/_binarySearchCutoffIndex.test.ts b/src/internal/binarySearchCutoffIndex.test.ts
similarity index 86%
rename from src/_binarySearchCutoffIndex.test.ts
rename to src/internal/binarySearchCutoffIndex.test.ts
index c957dff..0d757ee 100644
--- a/src/_binarySearchCutoffIndex.test.ts
+++ b/src/internal/binarySearchCutoffIndex.test.ts
@@ -1,29 +1,29 @@
-import { _binarySearchCutoffIndex } from "./_binarySearchCutoffIndex";
+import { binarySearchCutoffIndex } from "./binarySearchCutoffIndex";
 
 describe("runtime correctness", () => {
   test("empty array", () => {
-    expect(_binarySearchCutoffIndex([], () => true)).toBe(0);
+    expect(binarySearchCutoffIndex([], () => true)).toBe(0);
   });
 
   test("single value, always false", () => {
-    expect(_binarySearchCutoffIndex([1], () => false)).toBe(0);
+    expect(binarySearchCutoffIndex([1], () => false)).toBe(0);
   });
 
   test("single value, always true", () => {
-    expect(_binarySearchCutoffIndex([1], () => true)).toBe(1);
+    expect(binarySearchCutoffIndex([1], () => true)).toBe(1);
   });
 
   test("multiple values, always false", () => {
-    expect(_binarySearchCutoffIndex([1, 2, 3, 4, 5], () => false)).toBe(0);
+    expect(binarySearchCutoffIndex([1, 2, 3, 4, 5], () => false)).toBe(0);
   });
 
   test("multiple values, always true", () => {
-    expect(_binarySearchCutoffIndex([1, 2, 3, 4, 5], () => true)).toBe(5);
+    expect(binarySearchCutoffIndex([1, 2, 3, 4, 5], () => true)).toBe(5);
   });
 
   test("fancy stuff", () => {
     expect(
-      _binarySearchCutoffIndex(
+      binarySearchCutoffIndex(
         ["a", "ab", "abc", "abcd", "abcde"],
         ({ length }) => length < 3,
       ),
@@ -168,7 +168,7 @@ function indicesSeen(
   predicate: (item: unknown, index: number) => boolean,
 ): ReadonlyArray<number> {
   const indices: Array<number> = [];
-  _binarySearchCutoffIndex(items, (pivot, index) => {
+  binarySearchCutoffIndex(items, (pivot, index) => {
     indices.push(index);
     return predicate(pivot, index);
   });
diff --git a/src/_heap.test.ts b/src/internal/heap.test.ts
similarity index 92%
rename from src/_heap.test.ts
rename to src/internal/heap.test.ts
index fba7983..cafd449 100644
--- a/src/_heap.test.ts
+++ b/src/internal/heap.test.ts
@@ -1,4 +1,4 @@
-import { heapMaybeInsert } from "./_heap";
+import { heapMaybeInsert } from "./heap";
 
 // TODO: This file only tests edge-cases which cannot be reached via the public
 // functions that use the heap functions. We can expand the testing for heap so
diff --git a/src/_reduceLazy.test.ts b/src/internal/reduceLazy.test.ts
similarity index 81%
rename from src/_reduceLazy.test.ts
rename to src/internal/reduceLazy.test.ts
index 0c2b0a7..b440ec0 100644
--- a/src/_reduceLazy.test.ts
+++ b/src/internal/reduceLazy.test.ts
@@ -1,11 +1,11 @@
-import { _reduceLazy } from "./_reduceLazy";
+import { reduceLazy } from "./reduceLazy";
 
 // _reduceLazy is tested via the functions that call it, but those tests lack
 // several edge cases which need to be tested on their own.
 describe("generic tests", () => {
   it("handles hasMany", () => {
     expect(
-      _reduceLazy([1, 2, 3], (value) => ({
+      reduceLazy([1, 2, 3], (value) => ({
         hasNext: true,
         hasMany: true,
         next: [value, value, value],
diff --git a/src/intersectionWith.test.ts b/src/intersectionWith.test.ts
index 87a2b9d..00c23c3 100644
--- a/src/intersectionWith.test.ts
+++ b/src/intersectionWith.test.ts
@@ -29,10 +29,8 @@ describe("intersectionWith", () => {
       expect(
         intersectionWith(
           other,
-          /*
-           * type inference doesn't work properly for the comparator's first parameter
-           * in data last variant
-           */
+          // type inference doesn't work properly for the comparator's first
+          // parameter in data last variant
           (a, b) => (a as (typeof source)[0]).id === b,
         )(source),
       ).toEqual(expected);
diff --git a/src/mapWithFeedback.test.ts b/src/mapWithFeedback.test.ts
index b27dfdc..e5f619d 100644
--- a/src/mapWithFeedback.test.ts
+++ b/src/mapWithFeedback.test.ts
@@ -112,7 +112,7 @@ describe("typing", () => {
   it("should return a tuple consisting of the initial value type even if the initial iterable contains a different type", () => {
     const result = mapWithFeedback(
       ["1", "2", "3", "4", "5"],
-      (acc, x) => acc + Number.parseInt(x),
+      (acc, x) => acc + Number.parseInt(x, 10),
       100,
     );
     expectTypeOf(result).toEqualTypeOf<
diff --git a/src/sample.test.ts b/src/sample.test.ts
index f9a15fc..c1c12af 100644
--- a/src/sample.test.ts
+++ b/src/sample.test.ts
@@ -1,4 +1,4 @@
-import type { NonEmptyArray } from "./_types";
+import type { NonEmptyArray } from "./internal/types";
 import { sample } from "./sample";
 
 describe("at runtime", () => {
@@ -93,12 +93,12 @@ describe("at runtime", () => {
       expect(result).toStrictEqual([]);
     });
 
-    it("throws on negative sample size", () => {
-      expect(() => sample([1, 2, 3], -1 as number)).toThrow();
+    it("Treats negative sample sizes as 0", () => {
+      expect(sample([1, 2, 3], -1 as number)).toStrictEqual([]);
     });
 
-    it("throws on non-integer sample size", () => {
-      expect(() => sample([1, 2, 3], 0.5)).toThrow();
+    it("rounds non-integer sample sizes", () => {
+      expect(sample([1, 2, 3], 0.5)).toHaveLength(1);
     });
   });
 });