{"id":25836109,"url":"https://github.com/selfrefactor/rambda-v9","last_synced_at":"2026-03-04T02:32:36.421Z","repository":{"id":276013856,"uuid":"927922861","full_name":"selfrefactor/rambda-v9","owner":"selfrefactor","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-05T19:27:38.000Z","size":162,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-26T19:44:05.573Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://selfrefactor.github.io/rambda-v9/","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/selfrefactor.png","metadata":{"files":{"readme":"docs/README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-05T19:05:41.000Z","updated_at":"2025-02-05T19:27:41.000Z","dependencies_parsed_at":"2025-02-05T20:42:34.578Z","dependency_job_id":"9a5b5ab3-e1dd-41c4-b6b9-0646c2715568","html_url":"https://github.com/selfrefactor/rambda-v9","commit_stats":null,"previous_names":["selfrefactor/rambda-v9"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/selfrefactor/rambda-v9","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambda-v9","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambda-v9/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambda-v9/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambda-v9/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/selfrefactor","download_url":"https://codeload.github.com/selfrefactor/rambda-v9/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambda-v9/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30070099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T01:03:42.280Z","status":"online","status_checked_at":"2026-03-04T02:00:07.464Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-01T01:39:58.446Z","updated_at":"2026-03-04T02:32:36.381Z","avatar_url":"https://github.com/selfrefactor.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rambda\n\n`Rambda` is smaller and faster alternative to the popular functional programming library **Ramda**. - [Documentation](https://selfrefactor.github.io/rambda/#/)\n\n[![codecov](https://codecov.io/gh/selfrefactor/rambda/branch/master/graph/badge.svg)](https://codecov.io/gh/selfrefactor/rambda)\n![Commit activity](https://img.shields.io/github/commit-activity/y/selfrefactor/rambda)\n![Library size](https://img.shields.io/bundlephobia/minzip/rambda)\n[![install size](https://packagephobia.com/badge?p=rambda)](https://packagephobia.com/result?p=rambda)\n[![PR's Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](https://github.com/selfrefactor/rambda/pulls)\n[![GitHub contributors](https://img.shields.io/github/contributors/selfrefactor/rambda.svg)](https://github.com/selfrefactor/rambda/graphs/contributors)\n\n## ❯ Example use\n\n```javascript\nimport { compose, map, filter } from 'rambda'\n\nconst result = compose(\n  map(x =\u003e x * 2),\n  filter(x =\u003e x \u003e 2)\n)([1, 2, 3, 4])\n// =\u003e [6, 8]\n```\n\nYou can test this example in \u003ca href=\"https://rambda.now.sh?const%20result%20%3D%20R.compose(%0A%20%20R.map(x%20%3D%3E%20x%20*%202)%2C%0A%20%20R.filter(x%20%3D%3E%20x%20%3E%202)%0A)(%5B1%2C%202%2C%203%2C%204%5D)%0A%0A%2F%2F%20%3D%3E%20%5B6%2C%208%5D\"\u003eRambda's REPL\u003c/a\u003e\n\n* [Differences between Rambda and Ramda](#differences-between-rambda-and-ramda)\n* [API](#api)\n* [Changelog](#-changelog)\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#-example-use)\n\n## ❯ Rambda's advantages\n\n### TypeScript included\n\nTypeScript definitions are included in the library, in comparison to **Ramda**, where you need to additionally install `@types/ramda`.\n\nStill, you need to be aware that functional programming features in `TypeScript` are in development, which means that using **R.compose/R.pipe** can be problematic.\n\nImportant - Rambda version `7.1.0`(or higher) requires TypeScript version `4.3.3`(or higher).\n\n### Understandable source code due to little usage of internals\n\n`Ramda` uses a lot of internals, which hides a lot of logic. Reading the full source code of a method can be challenging.\n\n### Better VSCode experience\n\nIf the project is written in Javascript, then `go to source definition` action will lead you to actual implementation of the method.\n\n### Immutable TS definitions\n\nYou can use immutable version of Rambda definitions, which is linted with ESLint `functional/prefer-readonly-type` plugin.\n\n```\nimport {add} from 'rambda/immutable'\n```\n\n### Deno support\n\nLatest version of **Ramba** available for `Deno` users is 3 years old. This is not the case with **Rambda** as most of recent releases are available for `Deno` users.\n\nAlso, `Rambda` provides you with included TS definitions:\n\n```\n// Deno extension(https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno)\n// is installed and initialized\nimport * as R from \"https://deno.land/x/rambda/mod.ts\";\nimport * as Ramda from \"https://deno.land/x/ramda/mod.ts\";\n\nR.add(1)('foo') // =\u003e will trigger warning in VSCode as it should\nRamda.add(1)('foo') // =\u003e will not trigger warning in VSCode\n```\n\n### Dot notation for `R.path`, `R.paths`, `R.assocPath` and `R.lensPath`\n\nStandard usage of `R.path` is `R.path(['a', 'b'], {a: {b: 1} })`.\n\nIn **Rambda** you have the choice to use dot notation(which is arguably more readable):\n\n```\nR.path('a.b', {a: {b: 1} })\n```\n\nPlease note that since path input is turned into array, i.e. if you want `R.path(['a','1', 'b'], {a: {'1': {b: 2}}})` to return `2`, you will have to pass array path, not string path. If you pass `a.1.b`, it will turn path input to `['a', 1, 'b']`.\nThe other side effect is in `R.assocPath` and `R.dissocPath`, where inputs such as `['a', '1', 'b']` will be turned into `['a', 1, 'b']`.\n\n### Comma notation for `R.pick` and `R.omit`\n\nSimilar to dot notation, but the separator is comma(`,`) instead of dot(`.`).\n\n```\nR.pick('a,b', {a: 1 , b: 2, c: 3} })\n// No space allowed between properties\n```\n\n### Speed\n\n**Rambda** is generally more performant than `Ramda` as the [benchmarks](#-benchmarks) can prove that.\n\n### Support\n\nOne of the main issues with `Ramda` is the slow process of releasing new versions. This is not the case with **Rambda** as releases are made on regular basis.\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#-rambdas-advantages)\n\n## ❯ Missing Ramda methods\n\n\u003cdetails\u003e\n\u003csummary\u003e\n  Click to see the full list of 46 Ramda methods not implemented in Rambda and their status.\n\u003c/summary\u003e\n\n- construct - Using classes is not very functional programming oriented.\n- constructN - same as above\n- into - no support for transducer as it is overly complex to implement, understand and read.\n- invert - overly complicated and limited use case\n- invertObj\n- invoker\n- keysIn - we shouldn't encourage extending object with `.prototype` \n- lift\n- liftN\n- mapAccum - `Ramda` example doesn't looks convincing\n- mapAccumRight\n- memoizeWith - hard to imagine its usage in context of `R.pipe`/`R.compose`\n- mergeDeepWith - limited use case\n- mergeDeepWithKey\n- mergeWithKey\n- nAry - hard to argument about and hard to create meaningful TypeScript definitions\n- nthArg - limited use case\n- o - enough TypeScript issues with `R.pipe`/`R.compose` to add more composition methods\n- otherwise - naming is confusing\n- pair - `left-pad` types of debacles happens partially because of such methods that should not be hidden, bur rather part of your code base even if they need to exist.\n- partialRight - I dislike `R.partial`, so I don't want to add more methods that are based on it\n- pipeWith\n- project - naming is confusing, but also limited use case\n- promap\n- reduceRight - I find `right/left` methods confusing so I added them only where it makes sense.\n- reduceWhile - functions with 4 inputs - I think that even 3 is too much\n- reduced\n- remove - nice name but it is too generic. Also, `Rambdax` has such method and there it works very differently\n- scan - hard to explain\n- sequence\n- splitWhenever\n- symmetricDifferenceWith\n- andThen\n- toPairsIn\n- transduce - currently is out of focus\n- traverse - same as above\n- unary\n- uncurryN\n- unfold - similar to `R.scan` and I find that it doesn't help with readability\n- unionWith - why it has its usage, I want to limit number of methods that accept more than 2 arguments\n- until\n- useWith - hard to explain\n- valuesIn\n- xprod - limited use case\n- thunkify\n- __ - placeholder method allows user to further customize the method call. While, it seems useful initially, the price is too high in terms of complexity for TypeScript definitions. If it is not easy exressable in TypeScript, it is not worth it as **Rambda** is a TypeScript first library.\n\nThe following methods are not going to be added(reason for exclusion is provided as a comment):\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#-missing-ramda-methods)\n  \n## ❯ Install\n\n- **yarn add rambda**\n\n- For UMD usage either use `./dist/rambda.umd.js` or the following CDN link:\n\n```\nhttps://unpkg.com/rambda@CURRENT_VERSION/dist/rambda.umd.js\n```\n\n- with deno\n\n```\nimport {add} from \"https://deno.land/x/rambda/mod.ts\";\n```\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#-install)\n\n## Differences between Rambda and Ramda\n\n- Rambda's **type** detects async functions and unresolved `Promises`. The returned values are `'Async'` and `'Promise'`.\n\n- Rambda's **type** handles *NaN* input, in which case it returns `NaN`.\n\n- Rambda's **forEach** can iterate over objects not only arrays.\n\n- Rambda's **map**, **filter**, **partition** when they iterate over objects, they pass property and input object as predicate's argument.\n\n- Rambda's **filter** returns empty array with bad input(`null` or `undefined`), while Ramda throws.\n\n- Ramda's **clamp** work with strings, while Rambda's method work only with numbers.\n\n- Ramda's **indexOf/lastIndexOf** work with strings and lists, while Rambda's method work only with lists as iterable input.\n\n- Error handling, when wrong inputs are provided, may not be the same. This difference will be better documented once all brute force tests are completed.\n\n- TypeScript definitions between `rambda` and `@types/ramda` may vary.\n\n\u003e If you need more **Ramda** methods in **Rambda**, you may either submit a `PR` or check the extended version of **Rambda** - [Rambdax](https://github.com/selfrefactor/rambdax). In case of the former, you may want to consult with [Rambda contribution guidelines.](CONTRIBUTING.md)\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#-differences-between-rambda-and-ramda)\n\n## ❯ Benchmarks\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\nClick to expand all benchmark results\n\nThere are methods which are benchmarked only with `Ramda` and `Rambda`(i.e. no `Lodash`).\n\nNote that some of these methods, are called with and without curring. This is done in order to give more detailed performance feedback.\n\nThe benchmarks results are produced from latest versions of *Rambda*, *Lodash*(4.17.21) and *Ramda*(0.30.1).\n\n\u003c/summary\u003e\n\nmethod | Rambda | Ramda | Lodash\n--- |--- | --- | ---\n *add* | 🚀 Fastest | 21.52% slower | 82.15% slower\n *adjust* | 8.48% slower | 🚀 Fastest | 🔳\n *all* | 🚀 Fastest | 7.18% slower | 🔳\n *allPass* | 🚀 Fastest | 88.25% slower | 🔳\n *allPass* | 🚀 Fastest | 98.56% slower | 🔳\n *and* | 🚀 Fastest | 89.09% slower | 🔳\n *any* | 🚀 Fastest | 92.87% slower | 45.82% slower\n *anyPass* | 🚀 Fastest | 98.25% slower | 🔳\n *append* | 🚀 Fastest | 2.07% slower | 🔳\n *applySpec* | 🚀 Fastest | 80.43% slower | 🔳\n *assoc* | 72.32% slower | 60.08% slower | 🚀 Fastest\n *clone* | 🚀 Fastest | 91.86% slower | 86.48% slower\n *compose* | 6.07% slower | 16.89% slower | 🚀 Fastest\n *converge* | 78.63% slower | 🚀 Fastest | 🔳\n *curry* | 🚀 Fastest | 28.86% slower | 🔳\n *curryN* | 🚀 Fastest | 41.05% slower | 🔳\n *defaultTo* | 🚀 Fastest | 48.91% slower | 🔳\n *drop* | 🚀 Fastest | 82.35% slower | 🔳\n *dropLast* | 🚀 Fastest | 86.74% slower | 🔳\n *equals* | 58.37% slower | 96.73% slower | 🚀 Fastest\n *filter* | 6.7% slower | 72.03% slower | 🚀 Fastest\n *find* | 🚀 Fastest | 85.14% slower | 42.65% slower\n *findIndex* | 🚀 Fastest | 86.48% slower | 72.27% slower\n *flatten* | 🚀 Fastest | 85.68% slower | 3.57% slower\n *ifElse* | 🚀 Fastest | 58.56% slower | 🔳\n *includes* | 🚀 Fastest | 81.64% slower | 🔳\n *indexOf* | 🚀 Fastest | 80.17% slower | 🔳\n *indexOf* | 🚀 Fastest | 82.2% slower | 🔳\n *init* | 🚀 Fastest | 92.24% slower | 13.3% slower\n *is* | 🚀 Fastest | 57.69% slower | 🔳\n *isEmpty* | 🚀 Fastest | 97.14% slower | 54.99% slower\n *last* | 🚀 Fastest | 93.43% slower | 5.28% slower\n *lastIndexOf* | 🚀 Fastest | 85.19% slower | 🔳\n *map* | 🚀 Fastest | 86.6% slower | 11.73% slower\n *match* | 🚀 Fastest | 44.83% slower | 🔳\n *merge* | 🚀 Fastest | 12.21% slower | 55.76% slower\n *none* | 🚀 Fastest | 96.48% slower | 🔳\n *objOf* | 🚀 Fastest | 38.05% slower | 🔳\n *omit* | 🚀 Fastest | 69.95% slower | 97.34% slower\n *over* | 🚀 Fastest | 56.23% slower | 🔳\n *path* | 37.81% slower | 77.81% slower | 🚀 Fastest\n *pick* | 🚀 Fastest | 19.07% slower | 80.2% slower\n *pipe* | 🚀 Fastest | 0.11% slower | 🔳\n *prop* | 🚀 Fastest | 87.95% slower | 🔳\n *propEq* | 🚀 Fastest | 91.92% slower | 🔳\n *range* | 🚀 Fastest | 61.8% slower | 57.44% slower\n *reduce* | 60.48% slower | 77.1% slower | 🚀 Fastest\n *repeat* | 48.57% slower | 68.98% slower | 🚀 Fastest\n *replace* | 33.45% slower | 33.99% slower | 🚀 Fastest\n *set* | 🚀 Fastest | 50.35% slower | 🔳\n *sort* | 🚀 Fastest | 40.23% slower | 🔳\n *sortBy* | 🚀 Fastest | 25.29% slower | 56.88% slower\n *split* | 🚀 Fastest | 55.37% slower | 17.64% slower\n *splitEvery* | 🚀 Fastest | 71.98% slower | 🔳\n *take* | 🚀 Fastest | 91.96% slower | 4.72% slower\n *takeLast* | 🚀 Fastest | 93.39% slower | 19.22% slower\n *test* | 🚀 Fastest | 82.34% slower | 🔳\n *type* | 🚀 Fastest | 48.6% slower | 🔳\n *uniq* | 🚀 Fastest | 84.9% slower | 🔳\n *uniqBy* | 51.93% slower | 🚀 Fastest | 🔳\n *uniqWith* | 8.29% slower | 🚀 Fastest | 🔳\n *uniqWith* | 14.23% slower | 🚀 Fastest | 🔳\n *update* | 🚀 Fastest | 52.35% slower | 🔳\n *view* | 🚀 Fastest | 76.15% slower | 🔳\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#-benchmarks)\n\n## ❯ Used by\n\n- [ESLint plugin Mocha](https://www.npmjs.com/package/eslint-plugin-mocha)\n\n- [WatermelonDB](https://github.com/Nozbe/WatermelonDB)\n\n- [Walmart Canada](https://www.walmart.ca) reported by [w-b-dev](https://github.com/w-b-dev) \n\n- [VSCode Slack integration](https://github.com/verydanny/vcslack)\n\n- [Webpack PostCSS](https://github.com/sectsect/webpack-postcss)\n\n- [MobX-State-Tree decorators](https://github.com/farwayer/mst-decorators)\n\n- [Rewrite of the Betaflight configurator](https://github.com/freshollie/fresh-configurator)\n\n- [MineFlayer plugin](https://github.com/G07cha/MineflayerArmorManager)\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#-used-by)\n\n## API\n\n### add\n\n```typescript\n\nadd(a: number, b: number): number\n```\n\nIt adds `a` and `b`.\n\n\u003e :boom: It doesn't work with strings, as the inputs are parsed to numbers before calculation.\n\n```javascript\nR.add(2, 3) // =\u003e  5\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nadd(a: number, b: number): number;\nadd(a: number): (b: number) =\u003e number;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.add\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function add(a, b){\n  if (arguments.length === 1) return _b =\u003e add(a, _b)\n\n  return Number(a) + Number(b)\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { add as addRamda } from 'ramda'\n\nimport { compareCombinations } from './_internals/testUtils.js'\nimport { add } from './add.js'\n\ntest('with number', () =\u003e {\n  expect(add(2, 3)).toBe(5)\n  expect(add(7)(10)).toBe(17)\n})\n\ntest('string is bad input', () =\u003e {\n  expect(add('foo', 'bar')).toBeNaN()\n})\n\ntest('ramda specs', () =\u003e {\n  expect(add('1', '2')).toBe(3)\n  expect(add(1, '2')).toBe(3)\n  expect(add(true, false)).toBe(1)\n  expect(add(null, null)).toBe(0)\n  expect(add(undefined, undefined)).toBeNaN()\n  expect(add(new Date(1), new Date(2))).toBe(3)\n})\n\nconst possibleInputs = [\n  /foo/,\n  'foo',\n  true,\n  3,\n  NaN,\n  4,\n  [],\n  Promise.resolve(1),\n]\n\ndescribe('brute force', () =\u003e {\n  compareCombinations({\n    fn          : add,\n    fnRamda     : addRamda,\n    firstInput  : possibleInputs,\n    secondInput : possibleInputs,\n    callback    : errorsCounters =\u003e {\n      expect(errorsCounters).toMatchInlineSnapshot(`\n        {\n          \"ERRORS_MESSAGE_MISMATCH\": 0,\n          \"ERRORS_TYPE_MISMATCH\": 0,\n          \"RESULTS_MISMATCH\": 0,\n          \"SHOULD_NOT_THROW\": 0,\n          \"SHOULD_THROW\": 0,\n          \"TOTAL_TESTS\": 64,\n        }\n      `)\n    },\n  })\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {add} from 'rambda'\n\ndescribe('R.add', () =\u003e {\n  it('happy', () =\u003e {\n    const result = add(4, 1)\n\n    result // $ExpectType number\n  })\n  it('curried', () =\u003e {\n    const result = add(4)(1)\n\n    result // $ExpectType number\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#add)\n\n### addIndex\n\n```typescript\n\naddIndex(originalFn: any): (fn: any) =\u003e (list: any[]) =\u003e any[]\n```\n\n```javascript\nconst result = R.addIndex(R.map)((val, idx) =\u003e val + idx + 1, [1, 2, 3])\n// =\u003e [2, 4, 6]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\naddIndex(originalFn: any): (fn: any) =\u003e (list: any[]) =\u003e any[];\naddIndex(originalFn: any): (fn: any, list: any[]) =\u003e any[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.addIndex\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { _concat } from './_internals/utils.js'\nimport { curryN } from './curryN.js'\n\nexport function addIndex(\n  originalFunction,\n  initialIndexFn = () =\u003e 0,\n  loopIndexChange = x =\u003e x + 1\n){\n  return curryN(originalFunction.length, function (){\n    const origFn = arguments[ 0 ]\n    const list = arguments[ arguments.length - 1 ]\n    let idx = initialIndexFn(list.length)\n    const args = Array.prototype.slice.call(arguments, 0)\n    args[ 0 ] = function (){\n      const result = origFn.apply(this, _concat(arguments, [ idx, list ]))\n      idx = loopIndexChange(idx)\n\n      return result\n    }\n\n    return originalFunction.apply(this, args)\n  })\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport * as R from 'ramda'\n\nimport { addIndex } from './addIndex.js'\nimport { map } from './map.js'\n\ntest('with R.pipe', () =\u003e {\n  const result = R.pipe(R.addIndex(R.map)((x, i) =\u003e x + i))([ 1, 2, 3 ])\n  expect(result).toEqual([ 1, 3, 5 ])\n})\n\ntest('happy', () =\u003e {\n  function mapFn(fn, list){\n    const willReturn = []\n    list.forEach(item =\u003e {\n      willReturn.push(fn(item))\n    })\n\n    return willReturn\n  }\n  const mapIndexed = addIndex(mapFn)\n  const fn2 = (val, idx) =\u003e val + idx + 5\n  const result = mapIndexed(fn2, [ 1, 2, 3 ])\n  expect(result).toEqual([ 6, 8, 10 ])\n})\n\ndescribe('unary functions like `map`', () =\u003e {\n  const times2 = function (x){\n    return x * 2\n  }\n  const addIndexParam = function (x, idx){\n    return x + idx\n  }\n  const squareEnds = function (\n    x, idx, list\n  ){\n    return idx === 0 || idx === list.length - 1 ? x * x : x\n  }\n  const mapIndexed = addIndex(map)\n\n  it('works just like a normal map', () =\u003e {\n    expect(mapIndexed(times2, [ 1, 2, 3, 4 ])).toEqual([ 2, 4, 6, 8 ])\n  })\n\n  it('passes the index as a second parameter to the callback', () =\u003e {\n    expect(mapIndexed(addIndexParam, [ 8, 6, 7, 5, 3, 0, 9 ])).toEqual([\n      8, 7, 9, 8, 7, 5, 15,\n    ])\n  })\n\n  it('passes the entire list as a third parameter to the callback', () =\u003e {\n    expect(mapIndexed(squareEnds, [ 8, 6, 7, 5, 3, 0, 9 ])).toEqual([\n      64, 6, 7, 5, 3, 0, 81,\n    ])\n  })\n\n  it('acts as a curried function', () =\u003e {\n    const makeSquareEnds = mapIndexed(squareEnds)\n    expect(makeSquareEnds([ 8, 6, 7, 5, 3, 0, 9 ])).toEqual([\n      64, 6, 7, 5, 3, 0, 81,\n    ])\n  })\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {addIndex, map, pipe} from 'rambda'\n\ndescribe('R.addIndex', () =\u003e {\n  it('happy', () =\u003e {\n    function mapFn\u003cT\u003e(fn: (x: T) =\u003e T, list: T[]) {\n      const willReturn: T[] = []\n      list.forEach(item =\u003e {\n        willReturn.push(fn(item))\n      })\n\n      return willReturn\n    }\n    const mapIndexed = addIndex(mapFn)\n    const fn = (val: number, idx: number, list: number[]) =\u003e\n      val + idx + 5 + list[0]\n    const result = mapIndexed(fn)([1, 2, 3])\n    result // $ExpectType any[]\n  })\n  it('with pipe', () =\u003e {\n    const result = pipe(\n      addIndex(map)((x: number, i: number) =\u003e {\n        return x + i\n      })\n    )([1, 2, 3])\n    result // $ExpectType any[]\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#addIndex)\n\n### addIndexRight\n\n```typescript\n\naddIndexRight(originalFn: any): (fn: any) =\u003e (list: any[]) =\u003e any[]\n```\n\nSame as `R.addIndex`, but it will passed indexes are decreasing, instead of increasing.\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\naddIndexRight(originalFn: any): (fn: any) =\u003e (list: any[]) =\u003e any[];\naddIndexRight(originalFn: any): (fn: any, list: any[]) =\u003e any[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.addIndexRight\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { addIndex } from './addIndex.js'\n\nexport function addIndexRight(originalFunction){\n  return addIndex(\n    originalFunction,\n    listLength =\u003e listLength - 1,\n    x =\u003e x - 1\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { addIndexRight } from './addIndexRight.js'\nimport { map } from './map.js'\n\ntest('happy', () =\u003e {\n  function mapFn(fn, list){\n    const willReturn = []\n    list.forEach(item =\u003e {\n      willReturn.push(fn(item))\n    })\n\n    return willReturn\n  }\n  const mapIndexed = addIndexRight(mapFn)\n  const fn2 = (val, idx) =\u003e val + idx + 5\n  expect(mapIndexed(fn2, [ 1, 2, 3 ])).toEqual([ 8, 8, 8 ])\n  const revmap = (fn, ary) =\u003e map(fn, ary)\n  const revmapIndexed = addIndexRight(revmap)\n  const result = revmapIndexed((val, idx) =\u003e idx + '-' + val,\n    [ 'f', 'o', 'o', 'b', 'a', 'r' ])\n\n  expect(result).toEqual([ '5-f', '4-o', '3-o', '2-b', '1-a', '0-r' ])\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#addIndexRight)\n\n### adjust\n\n```typescript\n\nadjust\u003cT\u003e(index: number, replaceFn: (x: T) =\u003e T, list: T[]): T[]\n```\n\nIt replaces `index` in array `list` with the result of `replaceFn(list[i])`.\n\n```javascript\nconst result = R.adjust(\n  0,\n  a =\u003e a + 1,\n  [0, 100]\n) // =\u003e [1, 100]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nadjust\u003cT\u003e(index: number, replaceFn: (x: T) =\u003e T, list: T[]): T[];\nadjust\u003cT\u003e(index: number, replaceFn: (x: T) =\u003e T): (list: T[]) =\u003e T[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.adjust\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { cloneList } from './_internals/cloneList.js'\nimport { curry } from './curry.js'\n\nfunction adjustFn(\n  index, replaceFn, list\n){\n  const actualIndex = index \u003c 0 ? list.length + index : index\n  if (index \u003e= list.length || actualIndex \u003c 0) return list\n\n  const clone = cloneList(list)\n  clone[ actualIndex ] = replaceFn(clone[ actualIndex ])\n\n  return clone\n}\n\nexport const adjust = curry(adjustFn)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { add } from './add.js'\nimport { adjust } from './adjust.js'\nimport { pipe } from './pipe.js'\n\nconst list = [ 0, 1, 2 ]\nconst expected = [ 0, 11, 2 ]\n\ntest('happy', () =\u003e {})\n\ntest('happy', () =\u003e {\n  expect(adjust(\n    1, add(10), list\n  )).toEqual(expected)\n})\n\ntest('with curring type 1 1 1', () =\u003e {\n  expect(adjust(1)(add(10))(list)).toEqual(expected)\n})\n\ntest('with curring type 1 2', () =\u003e {\n  expect(adjust(1)(add(10), list)).toEqual(expected)\n})\n\ntest('with curring type 2 1', () =\u003e {\n  expect(adjust(1, add(10))(list)).toEqual(expected)\n})\n\ntest('with negative index', () =\u003e {\n  expect(adjust(\n    -2, add(10), list\n  )).toEqual(expected)\n})\n\ntest('when index is out of bounds', () =\u003e {\n  const list = [ 0, 1, 2, 3 ]\n  expect(adjust(\n    4, add(1), list\n  )).toEqual(list)\n  expect(adjust(\n    -5, add(1), list\n  )).toEqual(list)\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#adjust)\n\n### all\n\n```typescript\n\nall\u003cT\u003e(predicate: (x: T) =\u003e boolean, list: T[]): boolean\n```\n\nIt returns `true`, if all members of array `list` returns `true`, when applied as argument to `predicate` function.\n\n```javascript\nconst list = [ 0, 1, 2, 3, 4 ]\nconst predicate = x =\u003e x \u003e -1\n\nconst result = R.all(predicate, list)\n// =\u003e true\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nall\u003cT\u003e(predicate: (x: T) =\u003e boolean, list: T[]): boolean;\nall\u003cT\u003e(predicate: (x: T) =\u003e boolean): (list: T[]) =\u003e boolean;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.all\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function all(predicate, list){\n  if (arguments.length === 1) return _list =\u003e all(predicate, _list)\n\n  for (let i = 0; i \u003c list.length; i++){\n    if (!predicate(list[ i ])) return false\n  }\n\n  return true\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { all } from './all.js'\n\nconst list = [ 0, 1, 2, 3, 4 ]\n\ntest('when true', () =\u003e {\n  const fn = x =\u003e x \u003e -1\n\n  expect(all(fn)(list)).toBeTrue()\n})\n\ntest('when false', () =\u003e {\n  const fn = x =\u003e x \u003e 2\n\n  expect(all(fn, list)).toBeFalse()\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {all} from 'rambda'\n\ndescribe('all', () =\u003e {\n  it('happy', () =\u003e {\n    const result = all(\n      x =\u003e {\n        x // $ExpectType number\n        return x \u003e 0\n      },\n      [1, 2, 3]\n    )\n    result // $ExpectType boolean\n  })\n  it('curried needs a type', () =\u003e {\n    const result = all\u003cnumber\u003e(x =\u003e {\n      x // $ExpectType number\n      return x \u003e 0\n    })([1, 2, 3])\n    result // $ExpectType boolean\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#all)\n\n### allPass\n\n```typescript\n\nallPass\u003cT\u003e(predicates: ((x: T) =\u003e boolean)[]): (input: T) =\u003e boolean\n```\n\nIt returns `true`, if all functions of `predicates` return `true`, when `input` is their argument.\n\n```javascript\nconst input = {\n  a : 1,\n  b : 2,\n}\nconst predicates = [\n  x =\u003e x.a === 1,\n  x =\u003e x.b === 2,\n]\nconst result = R.allPass(predicates)(input) // =\u003e true\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nallPass\u003cT\u003e(predicates: ((x: T) =\u003e boolean)[]): (input: T) =\u003e boolean;\nallPass\u003cT\u003e(predicates: ((...inputs: T[]) =\u003e boolean)[]): (...inputs: T[]) =\u003e boolean;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.allPass\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function allPass(predicates){\n  return (...input) =\u003e {\n    let counter = 0\n    while (counter \u003c predicates.length){\n      if (!predicates[ counter ](...input)){\n        return false\n      }\n      counter++\n    }\n\n    return true\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { allPass } from './allPass.js'\n\ntest('happy', () =\u003e {\n  const rules = [ x =\u003e typeof x === 'number', x =\u003e x \u003e 10, x =\u003e x * 7 \u003c 100 ]\n\n  expect(allPass(rules)(11)).toBeTrue()\n\n  expect(allPass(rules)(undefined)).toBeFalse()\n})\n\ntest('when returns true', () =\u003e {\n  const conditionArr = [ val =\u003e val.a === 1, val =\u003e val.b === 2 ]\n\n  expect(allPass(conditionArr)({\n    a : 1,\n    b : 2,\n  })).toBeTrue()\n})\n\ntest('when returns false', () =\u003e {\n  const conditionArr = [ val =\u003e val.a === 1, val =\u003e val.b === 3 ]\n\n  expect(allPass(conditionArr)({\n    a : 1,\n    b : 2,\n  })).toBeFalse()\n})\n\ntest('works with multiple inputs', () =\u003e {\n  const fn = function (\n    w, x, y, z\n  ){\n    return w + x === y + z\n  }\n  expect(allPass([ fn ])(\n    3, 3, 3, 3\n  )).toBeTrue()\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {allPass, filter} from 'rambda'\n\ndescribe('allPass', () =\u003e {\n  it('happy', () =\u003e {\n    const x = allPass\u003cnumber\u003e([\n      y =\u003e {\n        y // $ExpectType number\n        return typeof y === 'number'\n      },\n      y =\u003e {\n        return y \u003e 0\n      },\n    ])(11)\n\n    x // $ExpectType boolean\n  })\n  it('issue #642', () =\u003e {\n    const isGreater = (num: number) =\u003e num \u003e 5\n    const pred = allPass([isGreater])\n    const xs = [0, 1, 2, 3]\n\n    const filtered1 = filter(pred)(xs)\n    filtered1 // $ExpectType number[]\n    const filtered2 = xs.filter(pred)\n    filtered2 // $ExpectType number[]\n  })\n  it('issue #604', () =\u003e {\n    const plusEq = function(w: number, x: number, y: number, z: number) {\n      return w + x === y + z\n    }\n    const result = allPass([plusEq])(3, 3, 3, 3)\n\n    result // $ExpectType boolean\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#allPass)\n\n### always\n\n```typescript\n\nalways\u003cT\u003e(x: T): (...args: unknown[]) =\u003e T\n```\n\nIt returns function that always returns `x`.\n\n```javascript\nconst fn = R.always(7)\n\nconst result = fn()\n// =\u003e 7\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nalways\u003cT\u003e(x: T): (...args: unknown[]) =\u003e T;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.always\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function always(x){\n  return _ =\u003e x\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { always } from './always.js'\nimport { applySpec } from './applySpec.js'\n\ntest('happy', () =\u003e {\n  const fn = always(7)\n\n  expect(fn()).toBe(7)\n  expect(fn()).toBe(7)\n})\n\ntest('compatibility with applySpec', () =\u003e {\n  const spec = applySpec({ x : always('foo') })\n  expect(spec({})).toEqual({ x : 'foo' })\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {always} from 'rambda'\n\ndescribe('R.always', () =\u003e {\n  it('happy', () =\u003e {\n    const fn = always('foo')\n    fn // $ExpectType (...args: unknown[]) =\u003e string\n    const result = fn()\n    result // $ExpectType string\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#always)\n\n### and\n\n```typescript\n\nand\u003cT, U\u003e(x: T, y: U): T | U\n```\n\nLogical AND\n\n```javascript\nR.and(true, true); // =\u003e true\nR.and(false, true); // =\u003e false\nR.and(true, 'foo'); // =\u003e 'foo'\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nand\u003cT, U\u003e(x: T, y: U): T | U;\nand\u003cT\u003e(x: T): \u003cU\u003e(y: U) =\u003e T | U;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.and\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function and(a, b){\n  if (arguments.length === 1) return _b =\u003e and(a, _b)\n\n  return a \u0026\u0026 b\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { and } from './and.js'\n\ntest('happy', () =\u003e {\n  expect(and(1, 'foo')).toBe('foo')\n  expect(and(true, true)).toBeTrue()\n  expect(and(true)(true)).toBeTrue()\n  expect(and(true, false)).toBeFalse()\n  expect(and(false, true)).toBeFalse()\n  expect(and(false, false)).toBeFalse()\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {and} from 'rambda'\n\ndescribe('R.and', () =\u003e {\n  it('happy', () =\u003e {\n    const result = and(true, false)\n    result // $ExpectType boolean\n  })\n  it('curried', () =\u003e {\n    const result = and('foo')(1)\n    result // $ExpectType string | 1\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#and)\n\n### any\n\n```typescript\n\nany\u003cT\u003e(predicate: (x: T) =\u003e boolean, list: T[]): boolean\n```\n\nIt returns `true`, if at least one member of `list` returns true, when passed to a `predicate` function.\n\n```javascript\nconst list = [1, 2, 3]\nconst predicate = x =\u003e x * x \u003e 8\nR.any(fn, list)\n// =\u003e true\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nany\u003cT\u003e(predicate: (x: T) =\u003e boolean, list: T[]): boolean;\nany\u003cT\u003e(predicate: (x: T) =\u003e boolean): (list: T[]) =\u003e boolean;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.any\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function any(predicate, list){\n  if (arguments.length === 1) return _list =\u003e any(predicate, _list)\n\n  let counter = 0\n  while (counter \u003c list.length){\n    if (predicate(list[ counter ], counter)){\n      return true\n    }\n    counter++\n  }\n\n  return false\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { any } from './any.js'\n\nconst list = [ 1, 2, 3 ]\n\ntest('happy', () =\u003e {\n  expect(any(x =\u003e x \u003c 0, list)).toBeFalse()\n})\n\ntest('with curry', () =\u003e {\n  expect(any(x =\u003e x \u003e 2)(list)).toBeTrue()\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {any} from 'rambda'\n\ndescribe('R.any', () =\u003e {\n  it('happy', () =\u003e {\n    const result = any(\n      x =\u003e {\n        x // $ExpectType number\n        return x \u003e 2\n      },\n      [1, 2, 3]\n    )\n    result // $ExpectType boolean\n  })\n\n  it('when curried needs a type', () =\u003e {\n    const result = any\u003cnumber\u003e(x =\u003e {\n      x // $ExpectType number\n      return x \u003e 2\n    })([1, 2, 3])\n    result // $ExpectType boolean\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#any)\n\n### anyPass\n\n```typescript\n\nanyPass\u003cT\u003e(predicates: ((x: T) =\u003e boolean)[]): (input: T) =\u003e boolean\n```\n\nIt accepts list of `predicates` and returns a function. This function with its `input` will return `true`, if any of `predicates` returns `true` for this `input`.\n\n```javascript\nconst isBig = x =\u003e x \u003e 20\nconst isOdd = x =\u003e x % 2 === 1\nconst input = 11\n\nconst fn = R.anyPass(\n  [isBig, isOdd]\n)\n\nconst result = fn(input) \n// =\u003e true\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nanyPass\u003cT\u003e(predicates: ((x: T) =\u003e boolean)[]): (input: T) =\u003e boolean;\nanyPass\u003cT\u003e(predicates: ((...inputs: T[]) =\u003e boolean)[]): (...inputs: T[]) =\u003e boolean;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.anyPass\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function anyPass(predicates){\n  return (...input) =\u003e {\n    let counter = 0\n    while (counter \u003c predicates.length){\n      if (predicates[ counter ](...input)){\n        return true\n      }\n      counter++\n    }\n\n    return false\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { anyPass } from './anyPass.js'\n\ntest('happy', () =\u003e {\n  const rules = [ x =\u003e typeof x === 'string', x =\u003e x \u003e 10 ]\n  const predicate = anyPass(rules)\n  expect(predicate('foo')).toBeTrue()\n  expect(predicate(6)).toBeFalse()\n})\n\ntest('happy', () =\u003e {\n  const rules = [ x =\u003e typeof x === 'string', x =\u003e x \u003e 10 ]\n\n  expect(anyPass(rules)(11)).toBeTrue()\n  expect(anyPass(rules)(undefined)).toBeFalse()\n})\n\nconst obj = {\n  a : 1,\n  b : 2,\n}\n\ntest('when returns true', () =\u003e {\n  const conditionArr = [ val =\u003e val.a === 1, val =\u003e val.a === 2 ]\n\n  expect(anyPass(conditionArr)(obj)).toBeTrue()\n})\n\ntest('when returns false + curry', () =\u003e {\n  const conditionArr = [ val =\u003e val.a === 2, val =\u003e val.b === 3 ]\n\n  expect(anyPass(conditionArr)(obj)).toBeFalse()\n})\n\ntest('with empty predicates list', () =\u003e {\n  expect(anyPass([])(3)).toBeFalse()\n})\n\ntest('works with multiple inputs', () =\u003e {\n  const fn = function (\n    w, x, y, z\n  ){\n    console.log(\n      w, x, y, z\n    )\n\n    return w + x === y + z\n  }\n  expect(anyPass([ fn ])(\n    3, 3, 3, 3\n  )).toBeTrue()\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {anyPass, filter} from 'rambda'\n\ndescribe('anyPass', () =\u003e {\n  it('happy', () =\u003e {\n    const x = anyPass\u003cnumber\u003e([\n      y =\u003e {\n        y // $ExpectType number\n        return typeof y === 'number'\n      },\n      y =\u003e {\n        return y \u003e 0\n      },\n    ])(11)\n\n    x // $ExpectType boolean\n  })\n  it('issue #604', () =\u003e {\n    const plusEq = function(w: number, x: number, y: number, z: number) {\n      return w + x === y + z\n    }\n    const result = anyPass([plusEq])(3, 3, 3, 3)\n\n    result // $ExpectType boolean\n  })\n  it('issue #642', () =\u003e {\n    const isGreater = (num: number) =\u003e num \u003e 5\n    const pred = anyPass([isGreater])\n    const xs = [0, 1, 2, 3]\n\n    const filtered1 = filter(pred)(xs)\n    filtered1 // $ExpectType number[]\n    const filtered2 = xs.filter(pred)\n    filtered2 // $ExpectType number[]\n  })\n  it('functions as a type guard', () =\u003e {\n    const isString = (x: unknown): x is string =\u003e typeof x === 'string'\n    const isNumber = (x: unknown): x is number =\u003e typeof x === 'number'\n    const isBoolean = (x: unknown): x is boolean =\u003e typeof x === 'boolean'\n\n    const isStringNumberOrBoolean = anyPass([isString, isNumber, isBoolean])\n\n    isStringNumberOrBoolean // $ExpectType (input: unknown) =\u003e boolean\n\n    const aValue: unknown = 1\n\n    if (isStringNumberOrBoolean(aValue)) {\n      aValue // $ExpectType unknown\n    }\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#anyPass)\n\n### ap\n\n```typescript\n\nap\u003cT, U\u003e(fns: Array\u003c(a: T) =\u003e U\u003e[], vs: T[]): U[]\n```\n\nIt takes a list of functions and a list of values. Then it returns a list of values obtained by applying each function to each value.\n\n```javascript\nconst result = R.ap(\n  [\n    x =\u003e x + 1,\n    x =\u003e x + 2,\n  ],\n  [1, 2, 3]\n)\n// =\u003e [2, 3, 4, 3, 4, 5]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nap\u003cT, U\u003e(fns: Array\u003c(a: T) =\u003e U\u003e[], vs: T[]): U[];\nap\u003cT, U\u003e(fns: Array\u003c(a: T) =\u003e U\u003e): (vs: T[]) =\u003e U[];\nap\u003cR, A, B\u003e(fn: (r: R, a: A) =\u003e B, fn1: (r: R) =\u003e A): (r: R) =\u003e B;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.ap\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function ap(functions, input){\n  if (arguments.length === 1){\n    return _inputs =\u003e ap(functions, _inputs)\n  }\n\n  return functions.reduce((acc, fn) =\u003e [ ...acc, ...input.map(fn) ], [])\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { ap } from './ap.js'\n\nfunction mult2(x){\n  return x * 2\n}\nfunction plus3(x){\n  return x + 3\n}\n\ntest('happy', () =\u003e {\n  expect(ap([ mult2, plus3 ], [ 1, 2, 3 ])).toEqual([ 2, 4, 6, 4, 5, 6 ])\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#ap)\n\n### aperture\n\n```typescript\n\naperture\u003cN extends number, T\u003e(n: N, list: T[]): Array\u003cTuple\u003cT, N\u003e\u003e | []\n```\n\nIt returns a new list, composed of consecutive `n`-tuples from a `list`.\n\n```javascript\nconst result = R.aperture(2, [1, 2, 3, 4])\n// =\u003e [[1, 2], [2, 3], [3, 4]]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\naperture\u003cN extends number, T\u003e(n: N, list: T[]): Array\u003cTuple\u003cT, N\u003e\u003e | [];\naperture\u003cN extends number\u003e(n: N): \u003cT\u003e(list: T[]) =\u003e Array\u003cTuple\u003cT, N\u003e\u003e | [];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.aperture\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function aperture(step, list){\n  if (arguments.length === 1){\n    return _list =\u003e aperture(step, _list)\n  }\n  if (step \u003e list.length) return []\n  let idx = 0\n  const limit = list.length - (step - 1)\n  const acc = new Array(limit)\n  while (idx \u003c limit){\n    acc[ idx ] = list.slice(idx, idx + step)\n    idx += 1\n  }\n\n  return acc\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { aperture } from './aperture.js'\n\nconst list = [ 1, 2, 3, 4, 5, 6, 7 ]\n\ntest('happy', () =\u003e {\n  expect(aperture(1, list)).toEqual([ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ], [ 6 ], [ 7 ] ])\n  expect(aperture(2, list)).toEqual([\n    [ 1, 2 ],\n    [ 2, 3 ],\n    [ 3, 4 ],\n    [ 4, 5 ],\n    [ 5, 6 ],\n    [ 6, 7 ],\n  ])\n  expect(aperture(3, list)).toEqual([\n    [ 1, 2, 3 ],\n    [ 2, 3, 4 ],\n    [ 3, 4, 5 ],\n    [ 4, 5, 6 ],\n    [ 5, 6, 7 ],\n  ])\n  expect(aperture(8, list)).toEqual([])\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#aperture)\n\n### append\n\n```typescript\n\nappend\u003cT\u003e(xToAppend: T, iterable: T[]): T[]\n```\n\nIt adds element `x` at the end of `iterable`.\n\n```javascript\nconst x = 'foo'\n\nconst result = R.append(x, ['bar', 'baz'])\n// =\u003e ['bar', 'baz', 'foo']\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nappend\u003cT\u003e(xToAppend: T, iterable: T[]): T[];\nappend\u003cT, U\u003e(xToAppend: T, iterable: IsFirstSubtypeOfSecond\u003cT, U\u003e[]) : U[];\nappend\u003cT\u003e(xToAppend: T): \u003cU\u003e(iterable: IsFirstSubtypeOfSecond\u003cT, U\u003e[]) =\u003e U[];\nappend\u003cT\u003e(xToAppend: T): (iterable: T[]) =\u003e T[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.append\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { cloneList } from './_internals/cloneList.js'\n\nexport function append(x, input){\n  if (arguments.length === 1) return _input =\u003e append(x, _input)\n\n  if (typeof input === 'string') return input.split('').concat(x)\n\n  const clone = cloneList(input)\n  clone.push(x)\n\n  return clone\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { append } from './append.js'\n\ntest('happy', () =\u003e {\n  expect(append('tests', [ 'write', 'more' ])).toEqual([\n    'write',\n    'more',\n    'tests',\n  ])\n})\n\ntest('append to empty array', () =\u003e {\n  expect(append('tests')([])).toEqual([ 'tests' ])\n})\n\ntest('with strings', () =\u003e {\n  expect(append('o', 'fo')).toEqual([ 'f', 'o', 'o' ])\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {append, prepend} from 'rambda'\n\nconst listOfNumbers = [1, 2, 3]\nconst listOfNumbersAndStrings = [1, 'b', 3]\n\ndescribe('R.append/R.prepend', () =\u003e {\n  describe(\"with the same primitive type as the array's elements\", () =\u003e {\n    it('uncurried', () =\u003e {\n      // @ts-expect-error\n      append('d', listOfNumbers)\n      // @ts-expect-error\n      prepend('d', listOfNumbers)\n      append(4, listOfNumbers) // $ExpectType number[]\n      prepend(4, listOfNumbers) // $ExpectType number[]\n    })\n\n    it('curried', () =\u003e {\n      // @ts-expect-error\n      append('d')(listOfNumbers)\n      append(4)(listOfNumbers) // $ExpectType number[]\n      prepend(4)(listOfNumbers) // $ExpectType number[]\n    })\n  })\n\n  describe(\"with a subtype of the array's elements\", () =\u003e {\n    it('uncurried', () =\u003e {\n      // @ts-expect-error\n      append(true, listOfNumbersAndStrings)\n      append(4, listOfNumbersAndStrings) // $ExpectType (string | number)[]\n      prepend(4, listOfNumbersAndStrings) // $ExpectType (string | number)[]\n    })\n\n    it('curried', () =\u003e {\n      // @ts-expect-error\n      append(true)(listOfNumbersAndStrings)\n      append(4)(listOfNumbersAndStrings) // $ExpectType (string | number)[]\n      prepend(4)(listOfNumbersAndStrings) // $ExpectType (string | number)[]\n    })\n  })\n\n  describe(\"expanding the type of the array's elements\", () =\u003e {\n    it('uncurried', () =\u003e {\n      // @ts-expect-error\n      append('d', listOfNumbers)\n      append\u003cstring | number\u003e('d', listOfNumbers) // $ExpectType (string | number)[]\n      prepend\u003cstring | number\u003e('d', listOfNumbers) // $ExpectType (string | number)[]\n    })\n\n    it('curried', () =\u003e {\n      // @ts-expect-error\n      append('d')(listOfNumbers)\n      const appendD = append('d')\n      appendD\u003cstring | number\u003e(listOfNumbers) // $ExpectType (string | number)[]\n      const prependD = prepend('d')\n      prependD\u003cstring | number\u003e(listOfNumbers) // $ExpectType (string | number)[]\n    })\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#append)\n\n### apply\n\n```typescript\n\napply\u003cT = any\u003e(fn: (...args: any[]) =\u003e T, args: any[]): T\n```\n\nIt applies function `fn` to the list of arguments. \n\nThis is useful for creating a fixed-arity function from a variadic function. `fn` should be a bound function if context is significant.\n\n```javascript\nconst result = R.apply(Math.max, [42, -Infinity, 1337])\n// =\u003e 1337\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\napply\u003cT = any\u003e(fn: (...args: any[]) =\u003e T, args: any[]): T;\napply\u003cT = any\u003e(fn: (...args: any[]) =\u003e T): (args: any[]) =\u003e T;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.apply\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function apply(fn, args){\n  if (arguments.length === 1){\n    return _args =\u003e apply(fn, _args)\n  }\n\n  return fn.apply(this, args)\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { apply } from './apply.js'\nimport { bind } from './bind.js'\nimport { identity } from './identity.js'\n\ntest('happy', () =\u003e {\n  expect(apply(identity, [ 1, 2, 3 ])).toBe(1)\n})\n\ntest('applies function to argument list', () =\u003e {\n  expect(apply(Math.max, [ 1, 2, 3, -99, 42, 6, 7 ])).toBe(42)\n})\n\ntest('provides no way to specify context', () =\u003e {\n  const obj = {\n    method (){\n      return this === obj\n    },\n  }\n  expect(apply(obj.method, [])).toBeFalse()\n  expect(apply(bind(obj.method, obj), [])).toBeTrue()\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {apply, identity} from 'rambda'\n\ndescribe('R.apply', () =\u003e {\n  it('happy', () =\u003e {\n    const result = apply\u003cnumber\u003e(identity, [1, 2, 3])\n\n    result // $ExpectType number\n  })\n  it('curried', () =\u003e {\n    const fn = apply\u003cnumber\u003e(identity)\n    const result = fn([1, 2, 3])\n\n    result // $ExpectType number\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#apply)\n\n### applySpec\n\n```typescript\n\napplySpec\u003cSpec extends Record\u003cstring, AnyFunction\u003e\u003e(\n  spec: Spec\n): (\n  ...args: Parameters\u003cValueOfRecord\u003cSpec\u003e\u003e\n) =\u003e { [Key in keyof Spec]: ReturnType\u003cSpec[Key]\u003e }\n```\n\n\u003e :boom: The currying in this function works best with functions with 4 arguments or less. (arity of 4)\n\n```javascript\nconst fn = R.applySpec({\n  sum: R.add,\n  nested: { mul: R.multiply }\n})\nconst result = fn(2, 4) \n// =\u003e { sum: 6, nested: { mul: 8 } }\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\napplySpec\u003cSpec extends Record\u003cstring, AnyFunction\u003e\u003e(\n  spec: Spec\n): (\n  ...args: Parameters\u003cValueOfRecord\u003cSpec\u003e\u003e\n) =\u003e { [Key in keyof Spec]: ReturnType\u003cSpec[Key]\u003e };\napplySpec\u003cT\u003e(spec: any): (...args: unknown[]) =\u003e T;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.applySpec\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { isArray } from './_internals/isArray.js'\n\n// recursively traverse the given spec object to find the highest arity function\nexport function __findHighestArity(spec, max = 0){\n  for (const key in spec){\n    if (spec.hasOwnProperty(key) === false || key === 'constructor') continue\n\n    if (typeof spec[ key ] === 'object'){\n      max = Math.max(max, __findHighestArity(spec[ key ]))\n    }\n\n    if (typeof spec[ key ] === 'function'){\n      max = Math.max(max, spec[ key ].length)\n    }\n  }\n\n  return max\n}\n\nfunction __filterUndefined(){\n  const defined = []\n  let i = 0\n  const l = arguments.length\n  while (i \u003c l){\n    if (typeof arguments[ i ] === 'undefined') break\n    defined[ i ] = arguments[ i ]\n    i++\n  }\n\n  return defined\n}\n\nfunction __applySpecWithArity(\n  spec, arity, cache\n){\n  const remaining = arity - cache.length\n\n  if (remaining === 1)\n    return x =\u003e\n      __applySpecWithArity(\n        spec, arity, __filterUndefined(...cache, x)\n      )\n  if (remaining === 2)\n    return (x, y) =\u003e\n      __applySpecWithArity(\n        spec, arity, __filterUndefined(\n          ...cache, x, y\n        )\n      )\n  if (remaining === 3)\n    return (\n      x, y, z\n    ) =\u003e\n      __applySpecWithArity(\n        spec, arity, __filterUndefined(\n          ...cache, x, y, z\n        )\n      )\n  if (remaining === 4)\n    return (\n      x, y, z, a\n    ) =\u003e\n      __applySpecWithArity(\n        spec,\n        arity,\n        __filterUndefined(\n          ...cache, x, y, z, a\n        )\n      )\n  if (remaining \u003e 4)\n    return (...args) =\u003e\n      __applySpecWithArity(\n        spec, arity, __filterUndefined(...cache, ...args)\n      )\n\n  // handle spec as Array\n  if (isArray(spec)){\n    const ret = []\n    let i = 0\n    const l = spec.length\n    for (; i \u003c l; i++){\n      // handle recursive spec inside array\n      if (typeof spec[ i ] === 'object' || isArray(spec[ i ])){\n        ret[ i ] = __applySpecWithArity(\n          spec[ i ], arity, cache\n        )\n      }\n      // apply spec to the key\n      if (typeof spec[ i ] === 'function'){\n        ret[ i ] = spec[ i ](...cache)\n      }\n    }\n\n    return ret\n  }\n\n  // handle spec as Object\n  const ret = {}\n  // apply callbacks to each property in the spec object\n  for (const key in spec){\n    if (spec.hasOwnProperty(key) === false || key === 'constructor') continue\n\n    // apply the spec recursively\n    if (typeof spec[ key ] === 'object'){\n      ret[ key ] = __applySpecWithArity(\n        spec[ key ], arity, cache\n      )\n      continue\n    }\n\n    // apply spec to the key\n    if (typeof spec[ key ] === 'function'){\n      ret[ key ] = spec[ key ](...cache)\n    }\n  }\n\n  return ret\n}\n\nexport function applySpec(spec, ...args){\n  // get the highest arity spec function, cache the result and pass to __applySpecWithArity\n  const arity = __findHighestArity(spec)\n\n  if (arity === 0){\n    return () =\u003e ({})\n  }\n  const toReturn = __applySpecWithArity(\n    spec, arity, args\n  )\n\n  return toReturn\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { applySpec as applySpecRamda, nAry } from 'ramda'\n\nimport {\n  add,\n  always,\n  compose,\n  dec,\n  inc,\n  map,\n  path,\n  prop,\n  T,\n} from '../rambda.js'\nimport { applySpec } from './applySpec.js'\n\ntest('different than Ramda when bad spec', () =\u003e {\n  const result = applySpec({ sum : { a : 1 } })(1, 2)\n  const ramdaResult = applySpecRamda({ sum : { a : 1 } })(1, 2)\n  expect(result).toEqual({})\n  expect(ramdaResult).toEqual({ sum : { a : {} } })\n})\n\ntest('works with empty spec', () =\u003e {\n  expect(applySpec({})()).toEqual({})\n  expect(applySpec([])(1, 2)).toEqual({})\n  expect(applySpec(null)(1, 2)).toEqual({})\n})\n\ntest('works with unary functions', () =\u003e {\n  const result = applySpec({\n    v : inc,\n    u : dec,\n  })(1)\n  const expected = {\n    v : 2,\n    u : 0,\n  }\n  expect(result).toEqual(expected)\n})\n\ntest('works with binary functions', () =\u003e {\n  const result = applySpec({ sum : add })(1, 2)\n  expect(result).toEqual({ sum : 3 })\n})\n\ntest('works with nested specs', () =\u003e {\n  const result = applySpec({\n    unnested : always(0),\n    nested   : { sum : add },\n  })(1, 2)\n  const expected = {\n    unnested : 0,\n    nested   : { sum : 3 },\n  }\n  expect(result).toEqual(expected)\n})\n\ntest('works with arrays of nested specs', () =\u003e {\n  const result = applySpec({\n    unnested : always(0),\n    nested   : [ { sum : add } ],\n  })(1, 2)\n\n  expect(result).toEqual({\n    unnested : 0,\n    nested   : [ { sum : 3 } ],\n  })\n})\n\ntest('works with arrays of spec objects', () =\u003e {\n  const result = applySpec([ { sum : add } ])(1, 2)\n\n  expect(result).toEqual([ { sum : 3 } ])\n})\n\ntest('works with arrays of functions', () =\u003e {\n  const result = applySpec([ map(prop('a')), map(prop('b')) ])([\n    {\n      a : 'a1',\n      b : 'b1',\n    },\n    {\n      a : 'a2',\n      b : 'b2',\n    },\n  ])\n  const expected = [\n    [ 'a1', 'a2' ],\n    [ 'b1', 'b2' ],\n  ]\n  expect(result).toEqual(expected)\n})\n\ntest('works with a spec defining a map key', () =\u003e {\n  expect(applySpec({ map : prop('a') })({ a : 1 })).toEqual({ map : 1 })\n})\n\ntest('cannot retains the highest arity', () =\u003e {\n  const f = applySpec({\n    f1 : nAry(2, T),\n    f2 : nAry(5, T),\n  })\n  const fRamda = applySpecRamda({\n    f1 : nAry(2, T),\n    f2 : nAry(5, T),\n  })\n  expect(f).toHaveLength(0)\n  expect(fRamda).toHaveLength(5)\n})\n\ntest('returns a curried function', () =\u003e {\n  expect(applySpec({ sum : add })(1)(2)).toEqual({ sum : 3 })\n})\n\n// Additional tests\n// ============================================\ntest('arity', () =\u003e {\n  const spec = {\n    one   : x1 =\u003e x1,\n    two   : (x1, x2) =\u003e x1 + x2,\n    three : (\n      x1, x2, x3\n    ) =\u003e x1 + x2 + x3,\n  }\n  expect(applySpec(\n    spec, 1, 2, 3\n  )).toEqual({\n    one   : 1,\n    two   : 3,\n    three : 6,\n  })\n})\n\ntest('arity over 5 arguments', () =\u003e {\n  const spec = {\n    one   : x1 =\u003e x1,\n    two   : (x1, x2) =\u003e x1 + x2,\n    three : (\n      x1, x2, x3\n    ) =\u003e x1 + x2 + x3,\n    four : (\n      x1, x2, x3, x4\n    ) =\u003e x1 + x2 + x3 + x4,\n    five : (\n      x1, x2, x3, x4, x5\n    ) =\u003e x1 + x2 + x3 + x4 + x5,\n  }\n  expect(applySpec(\n    spec, 1, 2, 3, 4, 5\n  )).toEqual({\n    one   : 1,\n    two   : 3,\n    three : 6,\n    four  : 10,\n    five  : 15,\n  })\n})\n\ntest('curried', () =\u003e {\n  const spec = {\n    one   : x1 =\u003e x1,\n    two   : (x1, x2) =\u003e x1 + x2,\n    three : (\n      x1, x2, x3\n    ) =\u003e x1 + x2 + x3,\n  }\n  expect(applySpec(spec)(1)(2)(3)).toEqual({\n    one   : 1,\n    two   : 3,\n    three : 6,\n  })\n})\n\ntest('curried over 5 arguments', () =\u003e {\n  const spec = {\n    one   : x1 =\u003e x1,\n    two   : (x1, x2) =\u003e x1 + x2,\n    three : (\n      x1, x2, x3\n    ) =\u003e x1 + x2 + x3,\n    four : (\n      x1, x2, x3, x4\n    ) =\u003e x1 + x2 + x3 + x4,\n    five : (\n      x1, x2, x3, x4, x5\n    ) =\u003e x1 + x2 + x3 + x4 + x5,\n  }\n  expect(applySpec(spec)(1)(2)(3)(4)(5)).toEqual({\n    one   : 1,\n    two   : 3,\n    three : 6,\n    four  : 10,\n    five  : 15,\n  })\n})\n\ntest('undefined property', () =\u003e {\n  const spec = { prop : path([ 'property', 'doesnt', 'exist' ]) }\n  expect(applySpec(spec, {})).toEqual({ prop : undefined })\n})\n\ntest('restructure json object', () =\u003e {\n  const spec = {\n    id          : path('user.id'),\n    name        : path('user.firstname'),\n    profile     : path('user.profile'),\n    doesntExist : path('user.profile.doesntExist'),\n    info        : { views : compose(inc, prop('views')) },\n    type        : always('playa'),\n  }\n\n  const data = {\n    user : {\n      id        : 1337,\n      firstname : 'john',\n      lastname  : 'shaft',\n      profile   : 'shaft69',\n    },\n    views : 42,\n  }\n\n  expect(applySpec(spec, data)).toEqual({\n    id          : 1337,\n    name        : 'john',\n    profile     : 'shaft69',\n    doesntExist : undefined,\n    info        : { views : 43 },\n    type        : 'playa',\n  })\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {multiply, applySpec, inc, dec, add} from 'rambda'\n\ndescribe('applySpec', () =\u003e {\n  it('ramda 1', () =\u003e {\n    const result = applySpec({\n      v: inc,\n      u: dec,\n    })(1)\n    result // $ExpectType { v: number; u: number; }\n  })\n  it('ramda 1', () =\u003e {\n    interface Output {\n      sum: number,\n      multiplied: number,\n    }\n    const result = applySpec\u003cOutput\u003e({\n      sum: add,\n      multiplied: multiply,\n    })(1, 2)\n\n    result // $ExpectType Output\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#applySpec)\n\n### applyTo\n\n```typescript\n\napplyTo\u003cT, U\u003e(el: T, fn: (t: T) =\u003e U): U\n```\n\n```javascript\nconst result = R.applyTo(\n  1,\n  x =\u003e x + 1\n)\n// =\u003e 2\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\napplyTo\u003cT, U\u003e(el: T, fn: (t: T) =\u003e U): U;\napplyTo\u003cT\u003e(el: T): \u003cU\u003e(fn: (t: T) =\u003e U) =\u003e U;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.applyTo\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function applyTo(input, fn){\n  if (arguments.length === 1){\n    return _fn =\u003e applyTo(input, _fn)\n  }\n\n  return fn(input)\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { applyTo } from './applyTo.js'\nimport { multiply } from './multiply.js'\n\ntest('happy', () =\u003e {\n  expect(applyTo(21, multiply(2))).toBe(42)\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#applyTo)\n\n### ascend\n\n```typescript\n\nascend\u003cT\u003e(fn: (obj: T) =\u003e Ord, a: T, b: T): Ordering\n```\n\n```javascript\nconst result = R.sort(R.descend(x =\u003e x), [2, 1])\n// =\u003e [1, 2]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nascend\u003cT\u003e(fn: (obj: T) =\u003e Ord, a: T, b: T): Ordering;\nascend\u003cT\u003e(fn: (obj: T) =\u003e Ord): (a: T, b: T) =\u003e Ordering;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.ascend\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function createCompareFunction(\n  a, b, winner, loser\n){\n  if (a === b) return 0\n\n  return a \u003c b ? winner : loser\n}\n\nexport function ascend(\n  getFunction, a, b\n){\n  if (arguments.length === 1){\n    return (_a, _b) =\u003e ascend(\n      getFunction, _a, _b\n    )\n  }\n  const aValue = getFunction(a)\n  const bValue = getFunction(b)\n\n  return createCompareFunction(\n    aValue, bValue, -1, 1\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { ascend } from './ascend.js'\nimport { descend } from './descend.js'\nimport { sort } from './sort.js'\n\nconst people = [\n  {\n    name : 'Emma',\n    age  : 70,\n  },\n  {\n    name : 'Peter',\n    age  : 78,\n  },\n  {\n    name : 'Mikhail',\n    age  : 62,\n  },\n]\n\ntest('ascend', () =\u003e {\n  const result = sort(ascend(x =\u003e x?.age),\n    people)\n  const expected = [\n    {\n      name : 'Mikhail',\n      age  : 62,\n    },\n    {\n      name : 'Emma',\n      age  : 70,\n    },\n    {\n      name : 'Peter',\n      age  : 78,\n    },\n  ]\n  expect(result).toEqual(expected)\n})\n\ntest('descend', () =\u003e {\n  const result = sort(descend(x =\u003e x?.age),\n    people)\n  const expected = [\n    {\n      name : 'Peter',\n      age  : 78,\n    },\n    {\n      name : 'Emma',\n      age  : 70,\n    },\n    {\n      name : 'Mikhail',\n      age  : 62,\n    },\n  ]\n\n  expect(result).toEqual(expected)\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#ascend)\n\n### assoc\n\n```typescript\n\nassoc\u003cK extends PropertyKey\u003e(prop: K): {\n  \u003cT\u003e(val: T): \u003cU extends Record\u003cK, T\u003e\u003e(obj: U) =\u003e U\n```\n\nIt makes a shallow clone of `obj` with setting or overriding the property `prop` with `newValue`.\n\n\u003e :boom: This copies and flattens prototype properties\nonto the new object as well. All non-primitive properties are copied by\nreference.\n\n```javascript\nR.assoc('c', 3, {a: 1, b: 2})\n// =\u003e {a: 1, b: 2, c: 3}\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nassoc\u003cK extends PropertyKey\u003e(prop: K): {\n  \u003cT\u003e(val: T): \u003cU extends Record\u003cK, T\u003e\u003e(obj: U) =\u003e U;\n  \u003cU extends Record\u003cK, T\u003e, T\u003e(val: T, obj: U): U;\n};\nassoc\u003cT, K extends PropertyKey\u003e(prop: K, val: T): {\n  \u003cU\u003e(obj: U): U extends Record\u003cK, any\u003e ? U[K] extends T ? U : Record\u003cK, T\u003e \u0026 Omit\u003cU, K\u003e : U \u0026 Record\u003cK, T\u003e;\n};\nassoc\u003cU, K extends keyof U, T extends U[K]\u003e(prop: K, val: T, obj: U): U;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.assoc\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { curry } from './curry.js'\n\nexport function assocFn(\n  prop, newValue, obj\n){\n  return Object.assign(\n    {}, obj, { [ prop ] : newValue }\n  )\n}\n\nexport const assoc = curry(assocFn)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { assoc } from './assoc.js'\n\ntest('adds a key to an empty object', () =\u003e {\n  expect(assoc(\n    'a', 1, {}\n  )).toEqual({ a : 1 })\n})\n\ntest('adds a key to a non-empty object', () =\u003e {\n  expect(assoc(\n    'b', 2, { a : 1 }\n  )).toEqual({\n    a : 1,\n    b : 2,\n  })\n})\n\ntest('adds a key to a non-empty object - curry case 1', () =\u003e {\n  expect(assoc('b', 2)({ a : 1 })).toEqual({\n    a : 1,\n    b : 2,\n  })\n})\n\ntest('adds a key to a non-empty object - curry case 2', () =\u003e {\n  expect(assoc('b')(2, { a : 1 })).toEqual({\n    a : 1,\n    b : 2,\n  })\n})\n\ntest('adds a key to a non-empty object - curry case 3', () =\u003e {\n  const result = assoc('b')(2)({ a : 1 })\n\n  expect(result).toEqual({\n    a : 1,\n    b : 2,\n  })\n})\n\ntest('changes an existing key', () =\u003e {\n  expect(assoc(\n    'a', 2, { a : 1 }\n  )).toEqual({ a : 2 })\n})\n\ntest('undefined is considered an empty object', () =\u003e {\n  expect(assoc(\n    'a', 1, undefined\n  )).toEqual({ a : 1 })\n})\n\ntest('null is considered an empty object', () =\u003e {\n  expect(assoc(\n    'a', 1, null\n  )).toEqual({ a : 1 })\n})\n\ntest('value can be null', () =\u003e {\n  expect(assoc(\n    'a', null, null\n  )).toEqual({ a : null })\n})\n\ntest('value can be undefined', () =\u003e {\n  expect(assoc(\n    'a', undefined, null\n  )).toEqual({ a : undefined })\n})\n\ntest('assignment is shallow', () =\u003e {\n  expect(assoc(\n    'a', { b : 2 }, { a : { c : 3 } }\n  )).toEqual({ a : { b : 2 } })\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport { assoc } from 'rambda'\n\ntype Obj = {\n  str: string\n  num: number\n}\n\nconst obj: Obj = { str: 'foo', num: 1 }\nconst newValue = 2\nconst newProp = 'num'\n\ndescribe('R.assoc', () =\u003e {\n  it('happy', () =\u003e {\n    const result = assoc(newProp, newValue, obj)\n\n    result.num // $ExpectType number\n    result.str // $ExpectType string\n  })\n  it('curried 1', () =\u003e {\n    const result = assoc(newProp, newValue)(obj)\n\n    result.num // $ExpectType number\n    result.str // $ExpectType string\n  })\n  it('curried 2', () =\u003e {\n    const result = assoc(newProp)(newValue)(obj)\n\n    result.num // $ExpectType number\n    result.str // $ExpectType string\n  })\n  it('from @types/ramda', () =\u003e {\n    // @ts-expect-error\n    assoc('str')(2, obj)\n    // @ts-expect-error\n    assoc('what')('bar', obj)\n\n    const result1 = assoc('what')(2, {} as Record\u003cstring, number\u003e)\n    result1.what // $ExpectType number\n\n    const result2 = assoc('str')('bar')(obj)\n    result2.str // $ExpectType string\n    result2.num // $ExpectType number\n\n    // @ts-expect-error\n    assoc('str')(2)(obj)\n    // @ts-expect-error\n    assoc('what')('foo')(obj)\n\n    const result3 = assoc('what')(2)({} as Record\u003cstring, number\u003e)\n    result3.what // $ExpectType number\n\n    const result4 = assoc('str', 'bar')(obj)\n    result4.str // $ExpectType string\n    result4.num // $ExpectType number\n\n    assoc('str', 2)(obj)\n    assoc('what', 'bar')(obj)\n\n    const result5 = assoc('str', 2)({} as Record\u003cstring, number\u003e)\n    result5.str // $ExpectType number\n\n    const result6 = assoc('str', 'bar', obj)\n    result6.str // $ExpectType string\n    result6.num // $ExpectType number\n\n    // @ts-expect-error\n    assoc('str', 2, obj)\n    // @ts-expect-error\n\n    assoc('what', 'bar', obj)\n\n    const result7 = assoc('str', 2, {} as Record\u003cstring, number\u003e)\n    result7.str // $ExpectType number\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#assoc)\n\n### assocPath\n\n```typescript\n\nassocPath\u003cOutput\u003e(path: Path, newValue: any, obj: object): Output\n```\n\nIt makes a shallow clone of `obj` with setting or overriding with `newValue` the property found with `path`.\n\n```javascript\nconst path = 'b.c'\nconst newValue = 2\nconst obj = { a: 1 }\n\nconst result = R.assocPath(path, newValue, obj)\n// =\u003e { a : 1, b : { c : 2 }}\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nassocPath\u003cOutput\u003e(path: Path, newValue: any, obj: object): Output;\nassocPath\u003cOutput\u003e(path: Path, newValue: any): (obj: object) =\u003e Output;\nassocPath\u003cOutput\u003e(path: Path): (newValue: any) =\u003e (obj: object) =\u003e Output;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.assocPath\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { cloneList } from './_internals/cloneList.js'\nimport { createPath } from './_internals/createPath.js'\nimport { isArray } from './_internals/isArray.js'\nimport { isIndexInteger } from './_internals/isInteger.js'\nimport { assocFn } from './assoc.js'\nimport { curry } from './curry.js'\n\nexport function assocPathFn(\n  path, newValue, input\n){\n  const pathArrValue = createPath(path)\n  if (pathArrValue.length === 0) return newValue\n\n  const index = pathArrValue[ 0 ]\n  if (pathArrValue.length \u003e 1){\n    const condition =\n      typeof input !== 'object' ||\n      input === null ||\n      !input.hasOwnProperty(index)\n\n    const nextInput = condition ?\n      isIndexInteger(pathArrValue[ 1 ]) ?\n        [] :\n        {} :\n      input[ index ]\n\n    newValue = assocPathFn(\n      Array.prototype.slice.call(pathArrValue, 1),\n      newValue,\n      nextInput\n    )\n  }\n\n  if (isIndexInteger(index) \u0026\u0026 isArray(input)){\n    const arr = cloneList(input)\n    arr[ index ] = newValue\n\n    return arr\n  }\n\n  return assocFn(\n    index, newValue, input\n  )\n}\n\nexport const assocPath = curry(assocPathFn)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { assocPathFn } from './assocPath.js'\n\ntest('happy', () =\u003e {\n  const path = 'a.c.1'\n  const input = {\n    a : {\n      b : 1,\n      c : [ 1, 2 ],\n    },\n  }\n  assocPathFn(\n    path, 3, input\n  )\n  expect(input).toEqual({\n    a : {\n      b : 1,\n      c : [ 1, 2 ],\n    },\n  })\n})\n\ntest('string can be used as path input', () =\u003e {\n  const testObj = {\n    a : [ { b : 1 }, { b : 2 } ],\n    d : 3,\n  }\n  const result1 = assocPathFn(\n    [ 'a', 0, 'b' ], 10, testObj\n  )\n  const result2 = assocPathFn(\n    'a.0.b', 10, testObj\n  )\n\n  const expected = {\n    a : [ { b : 10 }, { b : 2 } ],\n    d : 3,\n  }\n  expect(result1).toEqual(expected)\n  expect(result2).toEqual(expected)\n})\n\ntest('difference with ramda - doesn\\'t overwrite primitive values with keys in the path', () =\u003e {\n  const obj = { a : 'str' }\n  const result = assocPathFn(\n    [ 'a', 'b' ], 42, obj\n  )\n\n  expect(result).toEqual({\n    a : {\n      0 : 's',\n      1 : 't',\n      2 : 'r',\n      b : 42,\n    },\n  })\n})\n\ntest('adds a key to an empty object', () =\u003e {\n  expect(assocPathFn(\n    [ 'a' ], 1, {}\n  )).toEqual({ a : 1 })\n})\n\ntest('adds a key to a non-empty object', () =\u003e {\n  expect(assocPathFn(\n    'b', 2, { a : 1 }\n  )).toEqual({\n    a : 1,\n    b : 2,\n  })\n})\n\ntest('adds a nested key to a non-empty object', () =\u003e {\n  expect(assocPathFn(\n    'b.c', 2, { a : 1 }\n  )).toEqual({\n    a : 1,\n    b : { c : 2 },\n  })\n})\n\ntest('adds a nested key to a nested non-empty object', () =\u003e {\n  expect(assocPathFn('b.d',\n    3,{\n    a : 1,\n    b : { c : 2 },\n  })).toEqual({\n    a : 1,\n    b : {\n      c : 2,\n      d : 3,\n    },\n  })\n})\n\ntest('adds a key to a non-empty object', () =\u003e {\n  expect(assocPathFn('b', 2, { a : 1 })).toEqual({\n    a : 1,\n    b : 2,\n  })\n})\n\ntest('adds a nested key to a non-empty object', () =\u003e {\n  expect(assocPathFn('b.c', 2, { a : 1 })).toEqual({\n    a : 1,\n    b : { c : 2 },\n  })\n})\n\ntest('changes an existing key', () =\u003e {\n  expect(assocPathFn(\n    'a', 2, { a : 1 }\n  )).toEqual({ a : 2 })\n})\n\ntest('undefined is considered an empty object', () =\u003e {\n  expect(assocPathFn(\n    'a', 1, undefined\n  )).toEqual({ a : 1 })\n})\n\ntest('null is considered an empty object', () =\u003e {\n  expect(assocPathFn(\n    'a', 1, null\n  )).toEqual({ a : 1 })\n})\n\ntest('value can be null', () =\u003e {\n  expect(assocPathFn(\n    'a', null, null\n  )).toEqual({ a : null })\n})\n\ntest('value can be undefined', () =\u003e {\n  expect(assocPathFn(\n    'a', undefined, null\n  )).toEqual({ a : undefined })\n})\n\ntest('assignment is shallow', () =\u003e {\n  expect(assocPathFn(\n    'a', { b : 2 }, { a : { c : 3 } }\n  )).toEqual({ a : { b : 2 } })\n})\n\ntest('empty array as path', () =\u003e {\n  const result = assocPathFn(\n    [], 3, {\n      a : 1,\n      b : 2,\n    }\n  )\n  expect(result).toBe(3)\n})\n\ntest('happy', () =\u003e {\n  const expected = { foo : { bar : { baz : 42 } } }\n  const result = assocPathFn(\n    [ 'foo', 'bar', 'baz' ], 42, { foo : null }\n  )\n  expect(result).toEqual(expected)\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {assocPath} from 'rambda'\n\ninterface Output {\n  a: number,\n  foo: {bar: number},\n}\n\ndescribe('R.assocPath - user must explicitly set type of output', () =\u003e {\n  it('with array as path input', () =\u003e {\n    const result = assocPath\u003cOutput\u003e(['foo', 'bar'], 2, {a: 1})\n\n    result // $ExpectType Output\n  })\n  it('with string as path input', () =\u003e {\n    const result = assocPath\u003cOutput\u003e('foo.bar', 2, {a: 1})\n\n    result // $ExpectType Output\n  })\n})\n\ndescribe('R.assocPath - curried', () =\u003e {\n  it('with array as path input', () =\u003e {\n    const result = assocPath\u003cOutput\u003e(['foo', 'bar'], 2)({a: 1})\n\n    result // $ExpectType Output\n  })\n  it('with string as path input', () =\u003e {\n    const result = assocPath\u003cOutput\u003e('foo.bar', 2)({a: 1})\n\n    result // $ExpectType Output\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#assocPath)\n\n### binary\n\n```typescript\n\nbinary\u003cT extends (...arg: any[]) =\u003e any\u003e(fn: T): (...args: any[]) =\u003e ReturnType\u003cT\u003e\n```\n\n```javascript\nconst result = R.binary(\n  (a, b, c) =\u003e a + b + c,\n)(1, 2, 3, 4)\n// =\u003e 3\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nbinary\u003cT extends (...arg: any[]) =\u003e any\u003e(fn: T): (...args: any[]) =\u003e ReturnType\u003cT\u003e;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.binary\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function binary(fn){\n  if (fn.length \u003c= 2) return fn\n\n  return (a, b) =\u003e fn(a, b)\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { binary } from './binary.js'\n\ntest('happy', () =\u003e {\n  const result = binary(function (\n    x, y, z\n  ){\n    expect(arguments).toHaveLength(2)\n    expect(z).toBeUndefined()\n    expect(x).toBe(10)\n    expect(y).toBe(20)\n\n    return x + y\n  })(\n    10, 20, 30\n  )\n  expect(result).toBe(30)\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {binary} from 'rambda'\n\ndescribe('R.binary', () =\u003e {\n  it('happy', () =\u003e {\n    const result = binary(function(x: number, y: number, z) {\n      expect(arguments.length).toBe(2)\n      expect(z).toBeUndefined()\n      expect(x).toBe(10)\n      expect(y).toBe(20)\n      return x + y\n    })(10, 20, 30)\n    result // $ExpectType number\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#binary)\n\n### bind\n\n```typescript\n\nbind\u003cF extends AnyFunction, T\u003e(fn: F, thisObj: T): (...args: Parameters\u003cF\u003e) =\u003e ReturnType\u003cF\u003e\n```\n\nCreates a function that is bound to a context.\n\n\u003e :boom: R.bind does not provide the additional argument-binding capabilities of `Function.prototype.bind`.\n\n```javascript\nconst log = R.bind(console.log, console)\nconst result = R.pipe(\n  R.assoc('a', 2), \n  R.tap(log), \n  R.assoc('a', 3)\n)({a: 1}); \n// =\u003e result - `{a: 3}`\n// =\u003e console log - `{a: 2}`\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nbind\u003cF extends AnyFunction, T\u003e(fn: F, thisObj: T): (...args: Parameters\u003cF\u003e) =\u003e ReturnType\u003cF\u003e;\nbind\u003cF extends AnyFunction, T\u003e(fn: F): (thisObj: T) =\u003e (...args: Parameters\u003cF\u003e) =\u003e ReturnType\u003cF\u003e;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.bind\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { curryN } from './curryN.js'\n\nexport function bind(fn, thisObj){\n  if (arguments.length === 1){\n    return _thisObj =\u003e bind(fn, _thisObj)\n  }\n\n  return curryN(fn.length, (...args) =\u003e fn.apply(thisObj, args))\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { bind } from './bind.js'\n\nfunction Foo(x){\n  this.x = x\n}\nfunction add(x){\n  return this.x + x\n}\nfunction Bar(x, y){\n  this.x = x\n  this.y = y\n}\nBar.prototype = new Foo()\nBar.prototype.getX = function (){\n  return 'prototype getX'\n}\n\ntest('returns a function', () =\u003e {\n  expect(typeof bind(add)(Foo)).toBe('function')\n})\n\ntest('returns a function bound to the specified context object', () =\u003e {\n  const f = new Foo(12)\n  function isFoo(){\n    return this instanceof Foo\n  }\n  const isFooBound = bind(isFoo, f)\n  expect(isFoo()).toBeFalse()\n  expect(isFooBound()).toBeTrue()\n})\n\ntest('works with built-in types', () =\u003e {\n  const abc = bind(String.prototype.toLowerCase, 'ABCDEFG')\n  expect(typeof abc).toBe('function')\n  expect(abc()).toBe('abcdefg')\n})\n\ntest('works with user-defined types', () =\u003e {\n  const f = new Foo(12)\n  function getX(){\n    return this.x\n  }\n  const getXFooBound = bind(getX, f)\n  expect(getXFooBound()).toBe(12)\n})\n\ntest('works with plain objects', () =\u003e {\n  const pojso = { x : 100 }\n  function incThis(){\n    return this.x + 1\n  }\n  const incPojso = bind(incThis, pojso)\n  expect(typeof incPojso).toBe('function')\n  expect(incPojso()).toBe(101)\n})\n\ntest('does not interfere with existing object methods', () =\u003e {\n  const b = new Bar('a', 'b')\n  function getX(){\n    return this.x\n  }\n  const getXBarBound = bind(getX, b)\n  expect(b.getX()).toBe('prototype getX')\n  expect(getXBarBound()).toBe('a')\n})\n\ntest('preserves arity', () =\u003e {\n  const f0 = function (){\n    return 0\n  }\n  const f1 = function (a){\n    return a\n  }\n  const f2 = function (a, b){\n    return a + b\n  }\n  const f3 = function (\n    a, b, c\n  ){\n    return a + b + c\n  }\n\n  expect(bind(f0, {})).toHaveLength(0)\n  expect(bind(f1, {})).toHaveLength(1)\n  expect(bind(f2, {})).toHaveLength(2)\n  expect(bind(f3, {})).toHaveLength(3)\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {bind} from 'rambda'\n\nclass Foo {}\nfunction isFoo\u003cT = any\u003e(this: T): boolean {\n  return this instanceof Foo\n}\n\ndescribe('R.bind', () =\u003e {\n  it('happy', () =\u003e {\n    const foo = new Foo()\n    const result = bind(isFoo, foo)()\n\n    result // $ExpectType boolean\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#bind)\n\n### both\n\n```typescript\n\nboth(pred1: Pred, pred2: Pred): Pred\n```\n\nIt returns a function with `input` argument. \n\nThis function will return `true`, if both `firstCondition` and `secondCondition` return `true` when `input` is passed as their argument.\n\n```javascript\nconst firstCondition = x =\u003e x \u003e 10\nconst secondCondition = x =\u003e x \u003c 20\nconst fn = R.both(firstCondition, secondCondition)\n\nconst result = [fn(15), fn(30)]\n// =\u003e [true, false]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nboth(pred1: Pred, pred2: Pred): Pred;\nboth\u003cT\u003e(pred1: Predicate\u003cT\u003e, pred2: Predicate\u003cT\u003e): Predicate\u003cT\u003e;\nboth\u003cT\u003e(pred1: Predicate\u003cT\u003e): (pred2: Predicate\u003cT\u003e) =\u003e Predicate\u003cT\u003e;\nboth(pred1: Pred): (pred2: Pred) =\u003e Pred;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.both\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function both(f, g){\n  if (arguments.length === 1) return _g =\u003e both(f, _g)\n\n  return (...input) =\u003e f(...input) \u0026\u0026 g(...input)\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { both } from './both.js'\n\nconst firstFn = val =\u003e val \u003e 0\nconst secondFn = val =\u003e val \u003c 10\n\ntest('with curry', () =\u003e {\n  expect(both(firstFn)(secondFn)(17)).toBeFalse()\n})\n\ntest('without curry', () =\u003e {\n  expect(both(firstFn, secondFn)(7)).toBeTrue()\n})\n\ntest('with multiple inputs', () =\u003e {\n  const between = function (\n    a, b, c\n  ){\n    return a \u003c b \u0026\u0026 b \u003c c\n  }\n  const total20 = function (\n    a, b, c\n  ){\n    return a + b + c === 20\n  }\n  const fn = both(between, total20)\n  expect(fn(\n    5, 7, 8\n  )).toBeTrue()\n})\n\ntest('skip evaluation of the second expression', () =\u003e {\n  let effect = 'not evaluated'\n  const F = function (){\n    return false\n  }\n  const Z = function (){\n    effect = 'Z got evaluated'\n  }\n  both(F, Z)()\n\n  expect(effect).toBe('not evaluated')\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {both} from 'rambda'\n\ndescribe('R.both', () =\u003e {\n  it('with passed type', () =\u003e {\n    const fn = both\u003cnumber\u003e(\n      x =\u003e x \u003e 1,\n      x =\u003e x % 2 === 0\n    )\n    fn // $ExpectType Predicate\u003cnumber\u003e\n    const result = fn(2) // $ExpectType boolean\n    result // $ExpectType boolean\n  })\n  it('with passed type - curried', () =\u003e {\n    const fn = both\u003cnumber\u003e(x =\u003e x \u003e 1)(x =\u003e x % 2 === 0)\n    fn // $ExpectType Predicate\u003cnumber\u003e\n    const result = fn(2)\n    result // $ExpectType boolean\n  })\n  it('no type passed', () =\u003e {\n    const fn = both(\n      x =\u003e {\n        x // $ExpectType any\n        return x \u003e 1\n      },\n      x =\u003e {\n        x // $ExpectType any\n        return x % 2 === 0\n      }\n    )\n    const result = fn(2)\n    result // $ExpectType boolean\n  })\n  it('no type passed - curried', () =\u003e {\n    const fn = both((x: number) =\u003e {\n      x // $ExpectType number\n      return x \u003e 1\n    })((x: number) =\u003e {\n      x // $ExpectType number\n      return x % 2 === 0\n    })\n    const result = fn(2)\n    result // $ExpectType boolean\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#both)\n\n### call\n\n```typescript\n\ncall\u003cT extends (...args: any[]) =\u003e any\u003e(fn: T, ...args: Parameters\u003cT\u003e): ReturnType\u003cT\u003e\n```\n\n```javascript\nconst result = R.call(\n  (a, b) =\u003e a + b,\n  1,\n  2\n)\n// =\u003e 3\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ncall\u003cT extends (...args: any[]) =\u003e any\u003e(fn: T, ...args: Parameters\u003cT\u003e): ReturnType\u003cT\u003e;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.call\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport const call = (fn, ...inputs) =\u003e fn(...inputs)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { bind } from './bind.js'\nimport { call } from './call.js'\n\ntest('happy', () =\u003e {\n  expect(call(\n    Math.max, 1, 2, 3, -99, 42, 6, 7\n  )).toBe(42)\n})\n\ntest('accepts one or more arguments', () =\u003e {\n  const fn = function (){\n    return arguments.length\n  }\n  expect(call(fn)).toBe(0)\n  expect(call(fn, 'x')).toBe(1)\n  expect(call(\n    fn, 'x', 'y'\n  )).toBe(2)\n  expect(call(\n    fn, 'x', 'y', 'z'\n  )).toBe(3)\n})\n\ntest('provides no way to specify context', () =\u003e {\n  var obj = {\n    method (){\n      return this === obj\n    },\n  }\n  expect(call(obj.method)).toBe(false)\n  expect(call(bind(obj.method, obj))).toBe(true)\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#call)\n\n### chain\n\n```typescript\n\nchain\u003cT, U\u003e(fn: (n: T) =\u003e U[], list: T[]): U[]\n```\n\nThe method is also known as `flatMap`.\n\n```javascript\nconst duplicate = n =\u003e [ n, n ]\nconst list = [ 1, 2, 3 ]\n\nconst result = chain(duplicate, list)\n// =\u003e [ 1, 1, 2, 2, 3, 3 ]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nchain\u003cT, U\u003e(fn: (n: T) =\u003e U[], list: T[]): U[];\nchain\u003cT, U\u003e(fn: (n: T) =\u003e U[]): (list: T[]) =\u003e U[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.chain\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function chain(fn, list){\n  if (arguments.length === 1){\n    return _list =\u003e chain(fn, _list)\n  }\n\n  return [].concat(...list.map(fn))\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { chain as chainRamda } from 'ramda'\n\nimport { chain } from './chain.js'\n\nconst duplicate = n =\u003e [ n, n ]\n\ntest('happy', () =\u003e {\n  const fn = x =\u003e [ x * 2 ]\n  const list = [ 1, 2, 3 ]\n\n  const result = chain(fn, list)\n\n  expect(result).toEqual([ 2, 4, 6 ])\n})\n\ntest('maps then flattens one level', () =\u003e {\n  expect(chain(duplicate, [ 1, 2, 3 ])).toEqual([ 1, 1, 2, 2, 3, 3 ])\n})\n\ntest('maps then flattens one level - curry', () =\u003e {\n  expect(chain(duplicate)([ 1, 2, 3 ])).toEqual([ 1, 1, 2, 2, 3, 3 ])\n})\n\ntest('flattens only one level', () =\u003e {\n  const nest = n =\u003e [ [ n ] ]\n  expect(chain(nest, [ 1, 2, 3 ])).toEqual([ [ 1 ], [ 2 ], [ 3 ] ])\n})\n\ntest('can compose', () =\u003e {\n  function dec(x){\n    return [ x - 1 ]\n  }\n  function times2(x){\n    return [ x * 2 ]\n  }\n\n  const mdouble = chain(times2)\n  const mdec = chain(dec)\n  expect(mdec(mdouble([ 10, 20, 30 ]))).toEqual([ 19, 39, 59 ])\n})\n\ntest('@types/ramda broken test', () =\u003e {\n  const score = {\n    maths   : 90,\n    physics : 80,\n  }\n\n  const calculateTotal = score =\u003e {\n    const { maths, physics } = score\n\n    return maths + physics\n  }\n\n  const assocTotalToScore = (total, score) =\u003e ({\n    ...score,\n    total,\n  })\n\n  const calculateAndAssocTotalToScore = chainRamda(assocTotalToScore,\n    calculateTotal)\n  expect(() =\u003e\n    calculateAndAssocTotalToScore(score)).toThrowErrorMatchingInlineSnapshot('\"fn(...) is not a function\"')\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {chain} from 'rambda'\n\nconst list = [1, 2, 3]\nconst fn = (x: number) =\u003e [`${x}`, `${x}`]\n\ndescribe('R.chain', () =\u003e {\n  it('without passing type', () =\u003e {\n    const result = chain(fn, list)\n    result // $ExpectType string[]\n\n    const curriedResult = chain(fn)(list)\n    curriedResult // $ExpectType string[]\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#chain)\n\n### clamp\n\n```typescript\n\nclamp(min: number, max: number, input: number): number\n```\n\nRestrict a number `input` to be within `min` and `max` limits.\n\nIf `input` is bigger than `max`, then the result is `max`.\n\nIf `input` is smaller than `min`, then the result is `min`.\n\n```javascript\nconst result = [\n  R.clamp(0, 10, 5), \n  R.clamp(0, 10, -1),\n  R.clamp(0, 10, 11)\n]\n// =\u003e [5, 0, 10]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nclamp(min: number, max: number, input: number): number;\nclamp(min: number, max: number): (input: number) =\u003e number;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.clamp\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { curry } from './curry.js'\n\nfunction clampFn(\n  min, max, input\n){\n  if (min \u003e max){\n    throw new Error('min must not be greater than max in clamp(min, max, value)')\n  }\n  if (input \u003e= min \u0026\u0026 input \u003c= max) return input\n\n  if (input \u003e max) return max\n  if (input \u003c min) return min\n}\n\nexport const clamp = curry(clampFn)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { clamp } from './clamp.js'\n\ntest('when min is greater than max', () =\u003e {\n  expect(() =\u003e clamp(\n    -5, -10, 5\n  )).toThrowErrorMatchingInlineSnapshot('\"min must not be greater than max in clamp(min, max, value)\"')\n})\n\ntest('rambda specs', () =\u003e {\n  expect(clamp(\n    1, 10, 0\n  )).toBe(1)\n  expect(clamp(\n    3, 12, 1\n  )).toBe(3)\n  expect(clamp(\n    -15, 3, -100\n  )).toBe(-15)\n  expect(clamp(\n    1, 10, 20\n  )).toBe(10)\n  expect(clamp(\n    3, 12, 23\n  )).toBe(12)\n  expect(clamp(\n    -15, 3, 16\n  )).toBe(3)\n  expect(clamp(\n    1, 10, 4\n  )).toBe(4)\n  expect(clamp(\n    3, 12, 6\n  )).toBe(6)\n  expect(clamp(\n    -15, 3, 0\n  )).toBe(0)\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {clamp} from 'rambda'\n\ndescribe('R.clamp', () =\u003e {\n  it('happy', () =\u003e {\n    const result = clamp(1, 10, 20)\n    result // $ExpectType number\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#clamp)\n\n### clone\n\n```typescript\n\nclone\u003cT\u003e(input: T): T\n```\n\nIt creates a deep copy of the `input`, which may contain (nested) Arrays and Objects, Numbers, Strings, Booleans and Dates.\n\n\u003e :boom: It doesn't work with very specific types, such as MongoDB's ObjectId.\n\n```javascript\nconst objects = [{a: 1}, {b: 2}];\nconst objectsClone = R.clone(objects);\n\nconst result = [\n  R.equals(objects, objectsClone),\n  R.equals(objects[0], objectsClone[0]),\n] // =\u003e [ true, true ]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\nclone\u003cT\u003e(input: T): T;\nclone\u003cT\u003e(input: T[]): T[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.clone\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { isArray } from './_internals/isArray.js'\n\nexport function clone(input){\n  const out = isArray(input) ? Array(input.length) : {}\n  if (input \u0026\u0026 input.getTime) return new Date(input.getTime())\n\n  for (const key in input){\n    const v = input[ key ]\n    out[ key ] =\n      typeof v === 'object' \u0026\u0026 v !== null ?\n        v.getTime ?\n          new Date(v.getTime()) :\n          clone(v) :\n        v\n  }\n\n  return out\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport assert from 'assert'\nimport { clone as cloneRamda } from 'ramda'\n\nimport {\n  compareCombinations,\n  EXTRA_BUILD_IN_OBJECTS,\n  FALSY_VALUES,\n} from './_internals/testUtils.js'\nimport { clone } from './clone.js'\nimport { equals } from './equals.js'\n\ntest('with array', () =\u003e {\n  const arr = [\n    {\n      b : 2,\n      c : 'foo',\n      d : [ 1, 2, 3 ],\n    },\n    1,\n    new Date(),\n    null,\n  ]\n  expect(clone(arr)).toEqual(arr)\n})\n\ntest('with object', () =\u003e {\n  const obj = {\n    a : 1,\n    b : 2,\n    c : 3,\n    d : [ 1, 2, 3 ],\n    e : new Date(),\n  }\n  expect(clone(obj)).toEqual(obj)\n})\n\ntest('with date', () =\u003e {\n  const date = new Date(\n    2014, 10, 14, 23, 59, 59, 999\n  )\n\n  const cloned = clone(date)\n  assert.notStrictEqual(date, cloned)\n  expect(cloned).toEqual(new Date(\n    2014, 10, 14, 23, 59, 59, 999\n  ))\n\n  expect(cloned.getDay()).toBe(5)\n})\n\ntest('with R.equals', () =\u003e {\n  const objects = [ { a : 1 }, { b : 2 } ]\n\n  const objectsClone = clone(objects)\n\n  const result = [\n    equals(objects, objectsClone),\n    equals(objects[ 0 ], objectsClone[ 0 ]),\n  ]\n  expect(result).toEqual([ true, true ])\n})\n\ndescribe('brute force', () =\u003e {\n  const possibleInputs = [ ...FALSY_VALUES, ...EXTRA_BUILD_IN_OBJECTS ]\n  compareCombinations({\n    fn         : clone,\n    fnRamda    : cloneRamda,\n    firstInput : possibleInputs,\n    callback   : errorsCounters =\u003e {\n      expect(errorsCounters).toMatchInlineSnapshot(`\n        {\n          \"ERRORS_MESSAGE_MISMATCH\": 0,\n          \"ERRORS_TYPE_MISMATCH\": 0,\n          \"RESULTS_MISMATCH\": 15,\n          \"SHOULD_NOT_THROW\": 0,\n          \"SHOULD_THROW\": 0,\n          \"TOTAL_TESTS\": 15,\n        }\n      `)\n    },\n  })\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {clone} from 'rambda'\n\ndescribe('R.clone', () =\u003e {\n  it('happy', () =\u003e {\n    const obj = {a: 1, b: 2}\n    const result = clone(obj)\n    result // $ExpectType { a: number; b: number; }\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#clone)\n\n### collectBy\n\n```typescript\n\ncollectBy\u003cT, K extends PropertyKey\u003e(keyFn: (value: T) =\u003e K, list: T[]): T[][]\n```\n\n```javascript\nconst result = R.collectBy(\n  x =\u003e x % 2,\n  [1, 2, 3, 4]\n)\n// =\u003e [[2, 4], [1, 3]]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ncollectBy\u003cT, K extends PropertyKey\u003e(keyFn: (value: T) =\u003e K, list: T[]): T[][];\ncollectBy\u003cT, K extends PropertyKey\u003e(keyFn: (value: T) =\u003e K): (list: T[]) =\u003e T[][];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.collectBy\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { reduce } from './reduce.js'\n\nexport function collectBy(fn, list){\n  if (arguments.length === 1){\n    return _list =\u003e collectBy(fn, _list)\n  }\n\n  const group = reduce(\n    (o, x) =\u003e {\n      const tag = fn(x)\n      if (o[ tag ] === undefined){\n        o[ tag ] = []\n      }\n      o[ tag ].push(x)\n\n      return o\n    },\n    {},\n    list\n  )\n  const newList = []\n  for (const tag in group){\n    newList.push(group[ tag ])\n  }\n\n  return newList\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport fc from 'fast-check'\nimport {\n  all,\n  compose,\n  difference,\n  equals,\n  head,\n  identity,\n  is,\n  isEmpty,\n  length,\n  uniq,\n  unnest,\n} from 'rambdax'\n\nimport { collectBy } from './collectBy.js'\n\ntest('returns a list of lists', () =\u003e {\n  fc.assert(fc.property(fc.array(fc.nat()), xs =\u003e {\n    const check = all(is(Array))\n    const ys = collectBy(identity)(xs)\n\n    return check(ys)\n  }))\n})\n\ntest('groups items but neither adds new ones nor removes any', () =\u003e {\n  fc.assert(fc.property(fc.array(fc.nat()), xs =\u003e {\n    const check = compose(\n      isEmpty, difference(xs), unnest\n    )\n    const ys = collectBy(identity)(xs)\n\n    return check(ys)\n  }))\n})\n\ntest('groups related items together', () =\u003e {\n  fc.assert(fc.property(fc.array(fc.boolean()), xs =\u003e {\n    const ys = collectBy(identity)(xs)\n    const check = all(compose(\n      equals(1), length, uniq\n    ))\n\n    return check(ys)\n  }))\n})\n\ntest('invokes the tag function for each item in the list', () =\u003e {\n  fc.assert(fc.property(fc.array(fc.nat()), xs =\u003e {\n    const id = jest.fn(x =\u003e 42)\n    collectBy(id)(xs)\n    const check = compose(isEmpty, difference(xs))\n\n    return check(id.mock.calls.map(call =\u003e call[ 0 ]))\n  }))\n})\n\ntest('groups items according to the tag value', () =\u003e {\n  fc.assert(fc.property(fc.array(fc.nat()), xs =\u003e {\n    const ys = collectBy(x =\u003e 42)(xs)\n    const check = compose(\n      isEmpty, difference(xs), head\n    )\n\n    return isEmpty(xs) \u0026\u0026 isEmpty(ys) ? true : check(ys)\n  }))\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#collectBy)\n\n### comparator\n\n```typescript\n\ncomparator\u003cT\u003e(pred: (a: T, b: T) =\u003e boolean): (x: T, y: T) =\u003e Ordering\n```\n\nIt returns a comparator function that can be used in `sort` method.\n\n```javascript\nconst result = R.sort(\n  R.comparator((a, b) =\u003e a.x \u003c b.x),\n  [{x: 2}, {x: 1}]\n)\n// =\u003e [{x: 1}, {x: 2}]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ncomparator\u003cT\u003e(pred: (a: T, b: T) =\u003e boolean): (x: T, y: T) =\u003e Ordering;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.comparator\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function comparator(fn){\n  return function (a, b){\n    return fn(a, b) ? -1 : fn(b, a) ? 1 : 0\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { comparator } from './comparator.js'\n\ntest('happy', () =\u003e {\n  expect([ 3, 1, 8, 1, 2, 5 ].sort(comparator((a, b) =\u003e a \u003c b))).toEqual([\n    1, 1, 2, 3, 5, 8,\n  ])\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#comparator)\n\n### complement\n\n```typescript\n\ncomplement\u003cT extends any[]\u003e(predicate: (...args: T) =\u003e unknown): (...args: T) =\u003e boolean\n```\n\nIt returns `inverted` version of `origin` function that accept `input` as argument.\n\nThe return value of `inverted` is the negative boolean value of `origin(input)`.\n\n```javascript\nconst origin = x =\u003e x \u003e 5\nconst inverted = complement(origin)\n\nconst result = [\n  origin(7),\n  inverted(7)\n] =\u003e [ true, false ]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ncomplement\u003cT extends any[]\u003e(predicate: (...args: T) =\u003e unknown): (...args: T) =\u003e boolean;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.complement\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function complement(fn){\n  return (...input) =\u003e !fn(...input)\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { complement } from './complement.js'\n\ntest('happy', () =\u003e {\n  const fn = complement(x =\u003e x.length === 0)\n\n  expect(fn([ 1, 2, 3 ])).toBeTrue()\n})\n\ntest('with multiple parameters', () =\u003e {\n  const between = function (\n    a, b, c\n  ){\n    return a \u003c b \u0026\u0026 b \u003c c\n  }\n  const f = complement(between)\n  expect(f(\n    4, 5, 11\n  )).toBeFalse()\n  expect(f(\n    12, 2, 6\n  )).toBeTrue()\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {complement, isNil} from 'rambda'\n\ndescribe('R.complement', () =\u003e {\n  it('happy', () =\u003e {\n    const fn = complement(isNil)\n    const result = fn(null)\n    result // $ExpectType boolean\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#complement)\n\n### compose\n\n```typescript\n\ncompose\u003cTArgs extends any[], R1, R2, R3, R4, R5, R6, R7, TResult\u003e(\n  ...func: [\n      fnLast: (a: any) =\u003e TResult,\n      ...func: Array\u003c(a: any) =\u003e any\u003e,\n      f7: (a: R6) =\u003e R7,\n      f6: (a: R5) =\u003e R6,\n      f5: (a: R4) =\u003e R5,\n      f4: (a: R3) =\u003e R4,\n      f3: (a: R2) =\u003e R3,\n      f2: (a: R1) =\u003e R2,\n      f1: (...args: TArgs) =\u003e R1\n  ]\n): (...args: TArgs) =\u003e TResult\n```\n\nIt performs right-to-left function composition.\n\n```javascript\nconst result = R.compose(\n  R.map(x =\u003e x * 2),\n  R.filter(x =\u003e x \u003e 2)\n)([1, 2, 3, 4])\n\n// =\u003e [6, 8]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ncompose\u003cTArgs extends any[], R1, R2, R3, R4, R5, R6, R7, TResult\u003e(\n  ...func: [\n      fnLast: (a: any) =\u003e TResult,\n      ...func: Array\u003c(a: any) =\u003e any\u003e,\n      f7: (a: R6) =\u003e R7,\n      f6: (a: R5) =\u003e R6,\n      f5: (a: R4) =\u003e R5,\n      f4: (a: R3) =\u003e R4,\n      f3: (a: R2) =\u003e R3,\n      f2: (a: R1) =\u003e R2,\n      f1: (...args: TArgs) =\u003e R1\n  ]\n): (...args: TArgs) =\u003e TResult;\ncompose\u003cTArgs extends any[], R1, R2, R3, R4, R5, R6, R7, TResult\u003e(\n  f7: (a: R6) =\u003e R7,\n  f6: (a: R5) =\u003e R6,\n  f5: (a: R4) =\u003e R5,\n  f4: (a: R3) =\u003e R4,\n  f3: (a: R2) =\u003e R3,\n  f2: (a: R1) =\u003e R2,\n  f1: (...args: TArgs) =\u003e R1\n): (...args: TArgs) =\u003e R7;\ncompose\u003cTArgs extends any[], R1, R2, R3, R4, R5, R6, R7\u003e(\n  f7: (a: R6) =\u003e R7,\n  f6: (a: R5) =\u003e R6,\n  f5: (a: R4) =\u003e R5,\n  f4: (a: R3) =\u003e R4,\n  f3: (a: R2) =\u003e R3,\n  f2: (a: R1) =\u003e R2,\n  f1: (...args: TArgs) =\u003e R1\n): (...args: TArgs) =\u003e R7;\ncompose\u003cTArgs extends any[], R1, R2, R3, R4, R5, R6\u003e(\n  f6: (a: R5) =\u003e R6,\n  f5: (a: R4) =\u003e R5,\n  f4: (a: R3) =\u003e R4,\n  f3: (a: R2) =\u003e R3,\n  f2: (a: R1) =\u003e R2,\n  f1: (...args: TArgs) =\u003e R1\n): (...args: TArgs) =\u003e R6;\ncompose\u003cTArgs extends any[], R1, R2, R3, R4, R5\u003e(\n  f5: (a: R4) =\u003e R5,\n  f4: (a: R3) =\u003e R4,\n  f3: (a: R2) =\u003e R3,\n  f2: (a: R1) =\u003e R2,\n  f1: (...args: TArgs) =\u003e R1\n): (...args: TArgs) =\u003e R5;\ncompose\u003cTArgs extends any[], R1, R2, R3, R4\u003e(\n  f4: (a: R3) =\u003e R4,\n  f3: (a: R2) =\u003e R3,\n  f2: (a: R1) =\u003e R2,\n  f1: (...args: TArgs) =\u003e R1\n): (...args: TArgs) =\u003e R4;\ncompose\u003cTArgs extends any[], R1, R2, R3\u003e(\n  f3: (a: R2) =\u003e R3,\n  f2: (a: R1) =\u003e R2,\n  f1: (...args: TArgs) =\u003e R1\n): (...args: TArgs) =\u003e R3;\ncompose\u003cTArgs extends any[], R1, R2\u003e(\n  f2: (a: R1) =\u003e R2,\n  f1: (...args: TArgs) =\u003e R1\n): (...args: TArgs) =\u003e R2;\ncompose\u003cTArgs extends any[], R1\u003e(\n  f1: (...args: TArgs) =\u003e R1\n): (...args: TArgs) =\u003e R1;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.compose\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { pipe } from './pipe.js'\n\nexport function compose(){\n  if (arguments.length === 0){\n    throw new Error('compose requires at least one argument')\n  }\n\n  return pipe.apply(this, Array.prototype.slice.call(arguments, 0).reverse())\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { compose as composeRamda } from 'ramda'\n\nimport { add } from './add.js'\nimport { compose } from './compose.js'\nimport { filter } from './filter.js'\nimport { last } from './last.js'\nimport { map } from './map.js'\n\ntest('happy', () =\u003e {\n  const result = compose(\n    last, map(add(10)), map(add(1))\n  )([ 1, 2, 3 ])\n\n  expect(result).toBe(14)\n})\n\ntest('can accepts initially two arguments', () =\u003e {\n  const result = compose(map(x =\u003e x * 2),\n    (list, limit) =\u003e filter(x =\u003e x \u003e limit, list))([ 1, 2, 3, 4, false ], 2)\n\n  expect(result).toEqual([ 6, 8 ])\n})\n\ntest('when no arguments is passed', () =\u003e {\n  expect(() =\u003e compose()).toThrowErrorMatchingInlineSnapshot('\"compose requires at least one argument\"')\n})\n\ntest('ramda spec', () =\u003e {\n  const f = function (\n    a, b, c\n  ){\n    return [ a, b, c ]\n  }\n  const g = compose(f)\n\n  expect(g(\n    1, 2, 3\n  )).toEqual([ 1, 2, 3 ])\n})\n\ntest('does return correct length of composed function', () =\u003e {\n  expect(compose(\n    map, map, map\n  )).toHaveLength(2)\n  expect(composeRamda(\n    map, map, map\n  )).toHaveLength(2)\n})\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e test\u003c/summary\u003e\n\n```typescript\nimport {\n  add,\n  subtract,\n  compose,\n  map,\n  filter,\n  identity,\n  inc,\n  negate,\n  dissoc,\n} from 'rambda'\n\ninterface Input {\n  a: string,\n  b: string,\n}\ninterface Output {\n  c: string,\n}\n\ndescribe('R.compose with explicit types', () =\u003e {\n  it('with explicit types - complex', () =\u003e {\n    const obj = {\n      a: 'foo',\n      b: 'bar',\n    }\n    interface AfterInput {\n      a: number,\n    }\n    interface BeforeOutput {\n      b: string,\n    }\n\n    const result = compose\u003cInput[], AfterInput, BeforeOutput, Output\u003e(\n      x =\u003e ({c: x.b + 'bar'}),\n      x =\u003e ({b: x.a + 'foo'}),\n      x =\u003e ({a: x.a.length + x.b.length})\n    )(obj)\n\n    result // $ExpectType Output\n  })\n  it('with explicit types - correct', () =\u003e {\n    const obj = {\n      a: 'foo',\n      b: 'bar',\n    }\n    const result = compose\u003cInput[], Output, Output\u003e(identity, input =\u003e {\n      input // $ExpectType Input\n      return input as unknown as Output\n    })(obj)\n    result // $ExpectType Output\n  })\n  it('with explicit types - wrong', () =\u003e {\n    const obj: Input = {\n      a: 'foo',\n      b: 'bar',\n    }\n\n    // @ts-expect-error\n    compose\u003cstring, number, Output\u003e(identity, dissoc('b'))(obj)\n  })\n})\n\ndescribe('R.compose', () =\u003e {\n  it('happy', () =\u003e {\n    const result = compose(subtract(11), add(1), add(1))(1)\n    result // $ExpectType number\n  })\n  it('happy - more complex', () =\u003e {\n    const result = compose(\n      (x: number) =\u003e x + 1,\n      (x: string) =\u003e x.length + 1\n    )('foo')\n    result // $ExpectType number\n  })\n\n  it('with R.filter', () =\u003e {\n    const result = compose(\n      filter\u003cnumber\u003e(x =\u003e x \u003e 2),\n      map(add(1))\n    )([1, 2, 3])\n    result // $ExpectType number[]\n  })\n\n  it('with native filter', () =\u003e {\n    const result = compose(\n      (list: number[]) =\u003e list.filter(x =\u003e x \u003e 2),\n      (list: number[]) =\u003e {\n        list // $ExpectType number[]\n        return list\n      },\n      map(add(1))\n    )([1, 2, 3])\n\n    result // $ExpectType number[]\n  })\n\n  it('with void', () =\u003e {\n    const result = compose(\n      () =\u003e {},\n      () =\u003e {}\n    )()\n    result // $ExpectType void\n  })\n})\n\ndescribe('R.compose - @types/ramda tests', () =\u003e {\n  test('complex', () =\u003e {\n    const fn = compose(\n      inc,\n      inc,\n      inc,\n      inc,\n      inc,\n      inc,\n      inc,\n      inc,\n      negate,\n      Math.pow\n    )\n    const result = fn(3, 4)\n    result // $ExpectType number\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#compose)\n\n### composeWith\n\n```typescript\n\ncomposeWith\u003cTArgs extends any[], TResult\u003e(\n  transformer: (fn: (...args: any[]) =\u003e any, intermediatResult: any) =\u003e any,\n  fns: AtLeastOneFunctionsFlowFromRightToLeft\u003cTArgs, TResult\u003e,\n): (...args: TArgs) =\u003e TResult\n```\n\n```javascript\nconst result = R.composeWith(\n  (fn, intermediateResult) =\u003e fn(intermediateResult),\n  [\n    R.map(x =\u003e x + 1),\n    R.map(x =\u003e x * 2),\n  ]\n)([1, 2, 3])\n// =\u003e [3, 5, 7]\n```\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ncomposeWith\u003cTArgs extends any[], TResult\u003e(\n  transformer: (fn: (...args: any[]) =\u003e any, intermediatResult: any) =\u003e any,\n  fns: AtLeastOneFunctionsFlowFromRightToLeft\u003cTArgs, TResult\u003e,\n): (...args: TArgs) =\u003e TResult;\ncomposeWith(\n  transformer: (fn: (...args: any[]) =\u003e any, intermediatResult: any) =\u003e any,\n): \u003cTArgs extends any[], TResult\u003e(\n  fns: AtLeastOneFunctionsFlowFromRightToLeft\u003cTArgs, TResult\u003e,\n) =\u003e (...args: TArgs) =\u003e TResult;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.composeWith\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { _arity } from './_internals/_arity.js'\nimport { head } from './head.js'\nimport { identity } from './identity.js'\nimport { reduce } from './reduce.js'\nimport { reverse } from './reverse.js'\nimport { tail } from './tail.js'\n\nexport function pipeWith(xf, list){\n  if (list.length \u003c= 0){\n    return identity\n  }\n\n  const headList = head(list)\n  const tailList = tail(list)\n\n  return _arity(headList.length, function (){\n    return reduce(\n      function (result, f){\n        return xf.call(\n          this, f, result\n        )\n      },\n      headList.apply(this, arguments),\n      tailList\n    )\n  })\n}\n\nexport function composeWith(xf, list){\n  if (arguments.length === 1) return _list =\u003e composeWith(xf, _list)\n\n  return pipeWith.apply(this, [ xf, reverse(list) ])\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eTests\u003c/strong\u003e\u003c/summary\u003e\n\n```javascript\nimport { always, identity, inc, isNil, map, modulo, multiply } from 'rambdax'\nimport { composeWith as composeWithRamda, concat, flip, ifElse } from 'ramda'\n\nimport { composeWith } from './composeWith.js'\n\ntest('performs right-to-left function composition with function applying', () =\u003e {\n  const f = composeWith((f, res) =\u003e f(res))([ map, multiply, parseInt ])\n\n  expect(f).toHaveLength(2)\n  expect(f('10')([ 1, 2, 3 ])).toEqual([ 10, 20, 30 ])\n  expect(f('10', 2)([ 1, 2, 3 ])).toEqual([ 2, 4, 6 ])\n})\n\ntest('performs right-to-left function while not nil result', () =\u003e {\n  const isOdd = flip(modulo)(2)\n  const composeWhenNotNil = composeWithRamda((f, res) =\u003e\n    isNil(res) ? null : f(res))\n\n  const f = composeWhenNotNil([\n    inc,\n    ifElse(\n      isOdd, identity, always(null)\n    ),\n    parseInt,\n  ])\n  expect(f).toHaveLength(2)\n  expect(f('1')).toBe(2)\n  expect(f('2')).toBeNull()\n})\n\ntest('performs right-to-left function using promise chaining', () =\u003e {\n  const then = function (f, p){\n    return p.then(f)\n  }\n  const composeP = composeWithRamda(then)\n  const toListPromise = function (a){\n    return new Promise(res =\u003e {\n      res([ a ])\n    })\n  }\n  const doubleListPromise = function (a){\n    return new Promise(res =\u003e {\n      res(concat(a, a))\n    })\n  }\n  const f = composeP([ doubleListPromise, toListPromise ])\n\n  return f(1).then(res =\u003e {\n    expect(res).toEqual([ 1, 1 ])\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#composeWith)\n\n### concat\n\n```typescript\n\nconcat\u003cT\u003e(x: T","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselfrefactor%2Frambda-v9","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fselfrefactor%2Frambda-v9","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselfrefactor%2Frambda-v9/lists"}