{"id":13515354,"url":"https://github.com/selfrefactor/rambdax","last_synced_at":"2025-04-14T08:54:14.045Z","repository":{"id":40275343,"uuid":"87567927","full_name":"selfrefactor/rambdax","owner":"selfrefactor","description":"Extended version of Rambda ","archived":false,"fork":false,"pushed_at":"2025-04-01T14:31:29.000Z","size":5421,"stargazers_count":221,"open_issues_count":0,"forks_count":26,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-07T01:07:59.080Z","etag":null,"topics":["functional-programming","lodash","rambda","ramda","utils"],"latest_commit_sha":null,"homepage":"https://selfrefactor.github.io/rambdax","language":"JavaScript","has_issues":true,"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":".github/README.md","changelog":"CHANGELOG.md","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":"2017-04-07T16:54:26.000Z","updated_at":"2025-04-01T14:31:34.000Z","dependencies_parsed_at":"2024-05-03T12:25:15.518Z","dependency_job_id":"e28d33b8-77e8-4e4f-a72f-6a021b94db95","html_url":"https://github.com/selfrefactor/rambdax","commit_stats":{"total_commits":1025,"total_committers":20,"mean_commits":51.25,"dds":"0.030243902439024417","last_synced_commit":"d4ef6d78a39a6491223b9de79cd67308d4b9ccd6"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambdax","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambdax/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambdax/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selfrefactor%2Frambdax/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/selfrefactor","download_url":"https://codeload.github.com/selfrefactor/rambdax/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248852109,"owners_count":21171839,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["functional-programming","lodash","rambda","ramda","utils"],"created_at":"2024-08-01T05:01:09.982Z","updated_at":"2025-04-14T08:54:14.007Z","avatar_url":"https://github.com/selfrefactor.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","functional-programming","Libraries","Rambdax"],"sub_categories":["selfrefactor/rambdax"],"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[![CircleCI](https://circleci.com/gh/selfrefactor/rambda/tree/master.svg?style=svg)](https://circleci.com/gh/selfrefactor/rambda/tree/master)\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![All contributors](https://img.shields.io/github/contributors/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[![nest badge](https://nest.land/badge.svg)](https://nest.land/package/rambda)\n[![PR's Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](https://github.com/selfrefactor/rambda/pulls)\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\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\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.add(2%2C%203)%20%2F%2F%20%3D%3E%20%205\"\u003eTry this \u003cstrong\u003eR.add\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#add)\n\n### addIndex\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.addIndex(R.map)((val%2C%20idx)%20%3D%3E%20val%20%2B%20idx%20%2B%201%2C%20%5B1%2C%202%2C%203%5D)%0A%2F%2F%20%3D%3E%20%5B2%2C%204%2C%206%5D\"\u003eTry this \u003cstrong\u003eR.addIndex\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#addIndex)\n\n### addIndexRight\n\nSame as `R.addIndex`, but it will passed indexes are decreasing, instead of increasing.\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.adjust(%0A%20%200%2C%0A%20%20a%20%3D%3E%20a%20%2B%201%2C%0A%20%20%5B0%2C%20100%5D%0A)%20%2F%2F%20%3D%3E%20%5B1%2C%20100%5D\"\u003eTry this \u003cstrong\u003eR.adjust\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20list%20%3D%20%5B%200%2C%201%2C%202%2C%203%2C%204%20%5D%0Aconst%20predicate%20%3D%20x%20%3D%3E%20x%20%3E%20-1%0A%0Aconst%20result%20%3D%20R.all(predicate%2C%20list)%0A%2F%2F%20%3D%3E%20true\"\u003eTry this \u003cstrong\u003eR.all\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20input%20%3D%20%7B%0A%20%20a%20%3A%201%2C%0A%20%20b%20%3A%202%2C%0A%7D%0Aconst%20predicates%20%3D%20%5B%0A%20%20x%20%3D%3E%20x.a%20%3D%3D%3D%201%2C%0A%20%20x%20%3D%3E%20x.b%20%3D%3D%3D%202%2C%0A%5D%0Aconst%20result%20%3D%20R.allPass(predicates)(input)%20%2F%2F%20%3D%3E%20true\"\u003eTry this \u003cstrong\u003eR.allPass\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\nIt returns function that always returns `x`.\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20fn%20%3D%20R.always(7)%0A%0Aconst%20result%20%3D%20fn()%0A%2F%2F%20%3D%3E%207\"\u003eTry this \u003cstrong\u003eR.always\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#always)\n\n### and\n\nLogical AND\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?R.and(true%2C%20true)%3B%20%2F%2F%20%3D%3E%20true%0AR.and(false%2C%20true)%3B%20%2F%2F%20%3D%3E%20false%0Aconst%20result%20%3D%20R.and(true%2C%20'foo')%3B%20%2F%2F%20%3D%3E%20'foo'\"\u003eTry this \u003cstrong\u003eR.and\u003c/strong\u003e example in Rambda REPL\u003c/a\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20list%20%3D%20%5B1%2C%202%2C%203%5D%0Aconst%20predicate%20%3D%20x%20%3D%3E%20x%20*%20x%20%3E%208%0Aconst%20result%20%3D%20R.any(fn%2C%20list)%0A%2F%2F%20%3D%3E%20true\"\u003eTry this \u003cstrong\u003eR.any\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20isBig%20%3D%20x%20%3D%3E%20x%20%3E%2020%0Aconst%20isOdd%20%3D%20x%20%3D%3E%20x%20%25%202%20%3D%3D%3D%201%0Aconst%20input%20%3D%2011%0A%0Aconst%20fn%20%3D%20R.anyPass(%0A%20%20%5BisBig%2C%20isOdd%5D%0A)%0A%0Aconst%20result%20%3D%20fn(input)%20%0A%2F%2F%20%3D%3E%20true\"\u003eTry this \u003cstrong\u003eR.anyPass\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.ap(%0A%20%20%5B%0A%20%20%20%20x%20%3D%3E%20x%20%2B%201%2C%0A%20%20%20%20x%20%3D%3E%20x%20%2B%202%2C%0A%20%20%5D%2C%0A%20%20%5B1%2C%202%2C%203%5D%0A)%0A%2F%2F%20%3D%3E%20%5B2%2C%203%2C%204%2C%203%2C%204%2C%205%5D\"\u003eTry this \u003cstrong\u003eR.ap\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.aperture(2%2C%20%5B1%2C%202%2C%203%2C%204%5D)%0A%2F%2F%20%3D%3E%20%5B%5B1%2C%202%5D%2C%20%5B2%2C%203%5D%2C%20%5B3%2C%204%5D%5D\"\u003eTry this \u003cstrong\u003eR.aperture\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20x%20%3D%20'foo'%0A%0Aconst%20result%20%3D%20R.append(x%2C%20%5B'bar'%2C%20'baz'%5D)%0A%2F%2F%20%3D%3E%20%5B'bar'%2C%20'baz'%2C%20'foo'%5D\"\u003eTry this \u003cstrong\u003eR.append\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.apply(Math.max%2C%20%5B42%2C%20-Infinity%2C%201337%5D)%0A%2F%2F%20%3D%3E%201337\"\u003eTry this \u003cstrong\u003eR.apply\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20fn%20%3D%20R.applySpec(%7B%0A%20%20sum%3A%20R.add%2C%0A%20%20nested%3A%20%7B%20mul%3A%20R.multiply%20%7D%0A%7D)%0Aconst%20result%20%3D%20fn(2%2C%204)%20%0A%2F%2F%20%3D%3E%20%7B%20sum%3A%206%2C%20nested%3A%20%7B%20mul%3A%208%20%7D%20%7D\"\u003eTry this \u003cstrong\u003eR.applySpec\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.applyTo(%0A%20%201%2C%0A%20%20x%20%3D%3E%20x%20%2B%201%0A)%0A%2F%2F%20%3D%3E%202\"\u003eTry this \u003cstrong\u003eR.applyTo\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#applyTo)\n\n### ascend\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.sort(%0A%20%20R.ascend(x%20%3D%3E%20x)%2C%0A%20%20%5B2%2C%201%5D%0A)%0A%2F%2F%20%3D%3E%20%5B1%2C%202%5D\"\u003eTry this \u003cstrong\u003eR.ascend\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#ascend)\n\n### assoc\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.assoc('c'%2C%203%2C%20%7Ba%3A%201%2C%20b%3A%202%7D)%0A%2F%2F%20%3D%3E%20%7Ba%3A%201%2C%20b%3A%202%2C%20c%3A%203%7D\"\u003eTry this \u003cstrong\u003eR.assoc\u003c/strong\u003e example in Rambda REPL\u003c/a\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\nR.assocPath(path, newValue, Record\u003cstring, unknown\u003e)\n// =\u003e { a : 1, b : { c : 2 }}\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20path%20%3D%20'b.c'%0Aconst%20newValue%20%3D%202%0Aconst%20obj%20%3D%20%7B%20a%3A%201%20%7D%0A%0Aconst%20result%20%3D%20R.assocPath(path%2C%20newValue%2C%20Record%3Cstring%2C%20unknown%3E)%0A%2F%2F%20%3D%3E%20%7B%20a%20%3A%201%2C%20b%20%3A%20%7B%20c%20%3A%202%20%7D%7D\"\u003eTry this \u003cstrong\u003eR.assocPath\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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.only('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 = assocPath(\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('bug', () =\u003e {\n  /*\n    https://github.com/selfrefactor/rambda/issues/524\n  */\n  const state = {}\n\n  const withDateLike = assocPath(\n    [ 'outerProp', '2020-03-10' ],\n    { prop : 2 },\n    state\n  )\n  const withNumber = assocPath(\n    [ 'outerProp', '5' ], { prop : 2 }, state\n  )\n\n  const withDateLikeExpected = { outerProp : { '2020-03-10' : { prop : 2 } } }\n  const withNumberExpected = { outerProp : { 5 : { prop : 2 } } }\n  expect(withDateLike).toEqual(withDateLikeExpected)\n  expect(withNumber).toEqual(withNumberExpected)\n})\n\ntest('adds a key to an empty object', () =\u003e {\n  expect(assocPath(\n    [ 'a' ], 1, {}\n  )).toEqual({ a : 1 })\n})\n\ntest('adds a key to a non-empty object', () =\u003e {\n  expect(assocPath(\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(assocPath(\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 - curry case 1', () =\u003e {\n  expect(assocPath('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 - curry case 1', () =\u003e {\n  expect(assocPath('b', 2)({ a : 1 })).toEqual({\n    a : 1,\n    b : 2,\n  })\n})\n\ntest('adds a nested key to a non-empty object - curry case 1', () =\u003e {\n  expect(assocPath('b.c', 2)({ a : 1 })).toEqual({\n    a : 1,\n    b : { c : 2 },\n  })\n})\n\ntest('adds a key to a non-empty object - curry case 2', () =\u003e {\n  expect(assocPath('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 = assocPath('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(assocPath(\n    'a', 2, { a : 1 }\n  )).toEqual({ a : 2 })\n})\n\ntest('undefined is considered an empty object', () =\u003e {\n  expect(assocPath(\n    'a', 1, undefined\n  )).toEqual({ a : 1 })\n})\n\ntest('null is considered an empty object', () =\u003e {\n  expect(assocPath(\n    'a', 1, null\n  )).toEqual({ a : 1 })\n})\n\ntest('value can be null', () =\u003e {\n  expect(assocPath(\n    'a', null, null\n  )).toEqual({ a : null })\n})\n\ntest('value can be undefined', () =\u003e {\n  expect(assocPath(\n    'a', undefined, null\n  )).toEqual({ a : undefined })\n})\n\ntest('assignment is shallow', () =\u003e {\n  expect(assocPath(\n    'a', { b : 2 }, { a : { c : 3 } }\n  )).toEqual({ a : { b : 2 } })\n})\n\ntest('empty array as path', () =\u003e {\n  const result = assocPath(\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 = assocPath(\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.binary(%0A%20%20(a%2C%20b%2C%20c)%20%3D%3E%20a%20%2B%20b%20%2B%20c%2C%0A)(1%2C%202%2C%203%2C%204)%0A%2F%2F%20%3D%3E%203\"\u003eTry this \u003cstrong\u003eR.binary\u003c/strong\u003e example in Rambda REPL\u003c/a\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20log%20%3D%20R.bind(console.log%2C%20console)%0Aconst%20result%20%3D%20R.pipe(%0A%20%20R.assoc('a'%2C%202)%2C%20%0A%20%20R.tap(log)%2C%20%0A%20%20R.assoc('a'%2C%203)%0A)(%7Ba%3A%201%7D)%3B%20%0A%2F%2F%20%3D%3E%20result%20-%20%60%7Ba%3A%203%7D%60%0A%2F%2F%20%3D%3E%20console%20log%20-%20%60%7Ba%3A%202%7D%60\"\u003eTry this \u003cstrong\u003eR.bind\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20firstCondition%20%3D%20x%20%3D%3E%20x%20%3E%2010%0Aconst%20secondCondition%20%3D%20x%20%3D%3E%20x%20%3C%2020%0Aconst%20fn%20%3D%20R.both(firstCondition%2C%20secondCondition)%0A%0Aconst%20result%20%3D%20%5Bfn(15)%2C%20fn(30)%5D%0A%2F%2F%20%3D%3E%20%5Btrue%2C%20false%5D\"\u003eTry this \u003cstrong\u003eR.both\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.call(%0A%20%20(a%2C%20b)%20%3D%3E%20a%20%2B%20b%2C%0A%20%201%2C%0A%20%202%0A)%0A%2F%2F%20%3D%3E%203\"\u003eTry this \u003cstrong\u003eR.call\u003c/strong\u003e example in Rambda REPL\u003c/a\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20duplicate%20%3D%20n%20%3D%3E%20%5B%20n%2C%20n%20%5D%0Aconst%20list%20%3D%20%5B%201%2C%202%2C%203%20%5D%0A%0Aconst%20result%20%3D%20chain(duplicate%2C%20list)%0A%2F%2F%20%3D%3E%20%5B%201%2C%201%2C%202%2C%202%2C%203%2C%203%20%5D\"\u003eTry this \u003cstrong\u003eR.chain\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\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\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20%5B%0A%20%20R.clamp(0%2C%2010%2C%205)%2C%20%0A%20%20R.clamp(0%2C%2010%2C%20-1)%2C%0A%20%20R.clamp(0%2C%2010%2C%2011)%0A%5D%0A%2F%2F%20%3D%3E%20%5B5%2C%200%2C%2010%5D\"\u003eTry this \u003cstrong\u003eR.clamp\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#clamp)\n\n### clone\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20objects%20%3D%20%5B%7Ba%3A%201%7D%2C%20%7Bb%3A%202%7D%5D%3B%0Aconst%20objectsClone%20%3D%20R.clone(objects)%3B%0A%0Aconst%20result%20%3D%20%5B%0A%20%20R.equals(objects%2C%20objectsClone)%2C%0A%20%20R.equals(objects%5B0%5D%2C%20objectsClone%5B0%5D)%2C%0A%5D%20%2F%2F%20%3D%3E%20%5B%20true%2C%20true%20%5D\"\u003eTry this \u003cstrong\u003eR.clone\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#clone)\n\n### collectBy\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.collectBy(%0A%20%20x%20%3D%3E%20x%20%25%202%2C%0A%20%20%5B1%2C%202%2C%203%2C%204%5D%0A)%0A%2F%2F%20%3D%3E%20%5B%5B2%2C%204%5D%2C%20%5B1%2C%203%5D%5D\"\u003eTry this \u003cstrong\u003eR.collectBy\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#collectBy)\n\n### comparator\n\nIt returns a comparator function that can be used in `sort` method.\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.sort(%0A%20%20R.comparator((a%2C%20b)%20%3D%3E%20a.x%20%3C%20b.x)%2C%0A%20%20%5B%7Bx%3A%202%7D%2C%20%7Bx%3A%201%7D%5D%0A)%0A%2F%2F%20%3D%3E%20%5B%7Bx%3A%201%7D%2C%20%7Bx%3A%202%7D%5D\"\u003eTry this \u003cstrong\u003eR.comparator\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#comparator)\n\n### complement\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\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20origin%20%3D%20x%20%3D%3E%20x%20%3E%205%0Aconst%20inverted%20%3D%20complement(origin)%0A%0Aconst%20result%20%3D%20%5B%0A%20%20origin(7)%2C%0A%20%20inverted(7)%0A%5D%20%3D%3E%20%5B%20true%2C%20false%20%5D\"\u003eTry this \u003cstrong\u003eR.complement\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#complement)\n\n### compose\n\nIt performs right-to-left function composition.\n\n\u003ca title=\"redirect to Rambda Repl site\" 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\"\u003eTry this \u003cstrong\u003eR.compose\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#compose)\n\n### composeWith\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.composeWith(%0A%20%20(fn%2C%20intermediateResult)%20%3D%3E%20fn(intermediateResult)%2C%0A%20%20%5B%0A%20%20%20%20R.map(x%20%3D%3E%20x%20%2B%201)%2C%0A%20%20%20%20R.map(x%20%3D%3E%20x%20*%202)%2C%0A%20%20%5D%0A)(%5B1%2C%202%2C%203%5D)%0A%2F%2F%20%3D%3E%20%5B3%2C%205%2C%207%5D\"\u003eTry this \u003cstrong\u003eR.composeWith\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#composeWith)\n\n### concat\n\nIt returns a new string or array, which is the result of merging `x` and `y`.\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?R.concat(%5B1%2C%202%5D)(%5B3%2C%204%5D)%20%2F%2F%20%3D%3E%20%5B1%2C%202%2C%203%2C%204%5D%0Aconst%20result%20%3D%20R.concat('foo'%2C%20'bar')%20%2F%2F%20%3D%3E%20'foobar'\"\u003eTry this \u003cstrong\u003eR.concat\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#concat)\n\n### cond\n\nIt takes list with `conditions` and returns a new function `fn` that expects `input` as argument. \n\nThis function will start evaluating the `conditions` in order to find the first winner(order of conditions matter). \n\nThe winner is this condition, which left side returns `true` when `input` is its argument. Then the evaluation of the right side of the winner will be the final result.\n\nIf no winner is found, then `fn` returns `undefined`.\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20fn%20%3D%20R.cond(%5B%0A%20%20%5B%20x%20%3D%3E%20x%20%3E%2025%2C%20R.always('more%20than%2025')%20%5D%2C%0A%20%20%5B%20x%20%3D%3E%20x%20%3E%2015%2C%20R.always('more%20than%2015')%20%5D%2C%0A%20%20%5B%20R.T%2C%20x%20%3D%3E%20%60%24%7Bx%7D%20is%20nothing%20special%60%20%5D%2C%0A%5D)%0A%0Aconst%20result%20%3D%20%5B%0A%20%20fn(30)%2C%0A%20%20fn(20)%2C%0A%20%20fn(10)%2C%0A%5D%20%0A%2F%2F%20%3D%3E%20%5B'more%20than%2025'%2C%20'more%20than%2015'%2C%20'10%20is%20nothing%20special'%5D\"\u003eTry this \u003cstrong\u003eR.cond\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#cond)\n\n### converge\n\nAccepts a converging function and a list of branching functions and returns a new function. When invoked, this new function is applied to some arguments, each branching function is applied to those same arguments. The results of each branching function are passed as arguments to the converging function to produce the return value.\n\n\u003e :boom: Explanation is taken from `Ramda` documentation\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.converge(R.multiply)(%5B%20R.add(1)%2C%20R.add(3)%20%5D)(2)%0A%2F%2F%20%3D%3E%2015\"\u003eTry this \u003cstrong\u003eR.converge\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#converge)\n\n### count\n\nIt counts how many times `predicate` function returns `true`, when supplied with iteration of `list`.\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20list%20%3D%20%5B%7Ba%3A%201%7D%2C%201%2C%20%7Ba%3A2%7D%5D%0Aconst%20result%20%3D%20R.count(x%20%3D%3E%20x.a%20!%3D%3D%20undefined%2C%20list)%0A%2F%2F%20%3D%3E%202\"\u003eTry this \u003cstrong\u003eR.count\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#count)\n\n### countBy\n\n```typescript\n\ncountBy\u003cT extends unknown\u003e(transformFn: (x: T) =\u003e any, list: T[]): Record\u003cstring, number\u003e\n```\n\nIt counts elements in a list after each instance of the input list is passed through `transformFn` function.\n\n```javascript\nconst list = [ 'a', 'A', 'b', 'B', 'c', 'C' ]\n\nconst result = countBy(R.toLower, list)\nconst expected = { a: 2, b: 2, c: 2 }\n// =\u003e `result` is equal to `expected`\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20list%20%3D%20%5B%20'a'%2C%20'A'%2C%20'b'%2C%20'B'%2C%20'c'%2C%20'C'%20%5D%0A%0Aconst%20result%20%3D%20countBy(R.toLower%2C%20list)%0Aconst%20expected%20%3D%20%7B%20a%3A%202%2C%20b%3A%202%2C%20c%3A%202%20%7D%0A%2F%2F%20%3D%3E%20%60result%60%20is%20equal%20to%20%60expected%60\"\u003eTry this \u003cstrong\u003eR.countBy\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ncountBy\u003cT extends unknown\u003e(transformFn: (x: T) =\u003e any, list: T[]): Record\u003cstring, number\u003e;\ncountBy\u003cT extends unknown\u003e(transformFn: (x: T) =\u003e any): (list: T[]) =\u003e Record\u003cstring, number\u003e;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.countBy\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function countBy(fn, list){\n  if (arguments.length === 1){\n    return _list =\u003e countBy(fn, _list)\n  }\n  const willReturn = {}\n\n  list.forEach(item =\u003e {\n    const key = fn(item)\n    if (!willReturn[ key ]){\n      willReturn[ key ] = 1\n    } else {\n      willReturn[ key ]++\n    }\n  })\n\n  return willReturn\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 { countBy } from './countBy.js'\n\nconst list = [ 'a', 'A', 'b', 'B', 'c', 'C' ]\n\ntest('happy', () =\u003e {\n  const result = countBy(x =\u003e x.toLowerCase(), list)\n  expect(result).toEqual({\n    a : 2,\n    b : 2,\n    c : 2,\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 {countBy} from 'rambda'\n\nconst transformFn = (x: string) =\u003e x.toLowerCase()\nconst list = ['a', 'A', 'b', 'B', 'c', 'C']\n\ndescribe('R.countBy', () =\u003e {\n  it('happy', () =\u003e {\n    const result = countBy(transformFn, list)\n\n    result // $ExpectType Record\u003cstring, number\u003e\n  })\n  it('curried', () =\u003e {\n    const result = countBy(transformFn)(list)\n\n    result // $ExpectType Record\u003cstring, number\u003e\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#countBy)\n\n### curry\n\nIt expects a function as input and returns its curried version.\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20fn%20%3D%20(a%2C%20b%2C%20c)%20%3D%3E%20a%20%2B%20b%20%2B%20c%0Aconst%20curried%20%3D%20R.curry(fn)%0Aconst%20sum%20%3D%20curried(1%2C2)%0A%0Aconst%20result%20%3D%20sum(3)%20%2F%2F%20%3D%3E%206\"\u003eTry this \u003cstrong\u003eR.curry\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#curry)\n\n### curryN\n\nIt returns a curried equivalent of the provided function, with the specified arity.\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#curryN)\n\n### dec\n\nIt decrements a number.\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.dec(2)%20%2F%2F%20%3D%3E%201\"\u003eTry this \u003cstrong\u003eR.dec\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#dec)\n\n### defaultTo\n\n```typescript\n\ndefaultTo\u003cT\u003e(defaultValue: T, input: T | null | undefined): T\n```\n\nIt returns `defaultValue`, if all of `inputArguments` are `undefined`, `null` or `NaN`.\n\nElse, it returns the first truthy `inputArguments` instance(from left to right).\n\n\u003e :boom: Rambda's **defaultTo** accept indefinite number of arguments when non curried, i.e. `R.defaultTo(2, foo, bar, baz)`.\n\n```javascript\nR.defaultTo('foo', 'bar') // =\u003e 'bar'\nR.defaultTo('foo', undefined) // =\u003e 'foo'\n\n// Important - emtpy string is not falsy value(same as Ramda)\nR.defaultTo('foo', '') // =\u003e 'foo'\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?R.defaultTo('foo'%2C%20'bar')%20%2F%2F%20%3D%3E%20'bar'%0AR.defaultTo('foo'%2C%20undefined)%20%2F%2F%20%3D%3E%20'foo'%0A%0A%2F%2F%20Important%20-%20emtpy%20string%20is%20not%20falsy%20value(same%20as%20Ramda)%0Aconst%20result%20%3D%20R.defaultTo('foo'%2C%20'')%20%2F%2F%20%3D%3E%20'foo'\"\u003eTry this \u003cstrong\u003eR.defaultTo\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ndefaultTo\u003cT\u003e(defaultValue: T, input: T | null | undefined): T;\ndefaultTo\u003cT\u003e(defaultValue: T): (input: T | null | undefined) =\u003e T;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.defaultTo\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nfunction isFalsy(input){\n  return (\n    input === undefined || input === null || Number.isNaN(input) === true\n  )\n}\n\nexport function defaultTo(defaultArgument, input){\n  if (arguments.length === 1){\n    return _input =\u003e defaultTo(defaultArgument, _input)\n  }\n\n  return isFalsy(input) ? defaultArgument : 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 { defaultTo } from './defaultTo.js'\n\ntest('with undefined', () =\u003e {\n  expect(defaultTo('foo')(undefined)).toBe('foo')\n})\n\ntest('with null', () =\u003e {\n  expect(defaultTo('foo')(null)).toBe('foo')\n})\n\ntest('with NaN', () =\u003e {\n  expect(defaultTo('foo')(NaN)).toBe('foo')\n})\n\ntest('with empty string', () =\u003e {\n  expect(defaultTo('foo', '')).toBe('')\n})\n\ntest('with false', () =\u003e {\n  expect(defaultTo('foo', false)).toBeFalse()\n})\n\ntest('when inputArgument passes initial check', () =\u003e {\n  expect(defaultTo('foo', 'bar')).toBe('bar')\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 {defaultTo} from 'rambda'\n\ndescribe('R.defaultTo with Ramda spec', () =\u003e {\n  it('happy', () =\u003e {\n    const result = defaultTo('foo', '')\n    result // $ExpectType \"\" | \"foo\"\n  })\n  it('with explicit type', () =\u003e {\n    const result = defaultTo\u003cstring\u003e('foo', null)\n    result // $ExpectType string\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#defaultTo)\n\n### descend\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?R.sort(%0A%20%20R.descend(x%20%3D%3E%20x)%2C%0A%20%20%5B1%2C%202%5D%0Aconst%20result%20%3D%20)%0A%2F%2F%20%3D%3E%20%5B2%2C%201%5D\"\u003eTry this \u003cstrong\u003eR.descend\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#descend)\n\n### difference\n\n```typescript\n\ndifference\u003cT\u003e(a: T[], b: T[]): T[]\n```\n\nIt returns the uniq set of all elements in the first list `a` not contained in the second list `b`.\n\n`R.equals` is used to determine equality.\n\n```javascript\nconst a = [ 1, 2, 3, 4 ]\nconst b = [ 3, 4, 5, 6 ]\n\nconst result = R.difference(a, b)\n// =\u003e [ 1, 2 ]\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20a%20%3D%20%5B%201%2C%202%2C%203%2C%204%20%5D%0Aconst%20b%20%3D%20%5B%203%2C%204%2C%205%2C%206%20%5D%0A%0Aconst%20result%20%3D%20R.difference(a%2C%20b)%0A%2F%2F%20%3D%3E%20%5B%201%2C%202%20%5D\"\u003eTry this \u003cstrong\u003eR.difference\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ndifference\u003cT\u003e(a: T[], b: T[]): T[];\ndifference\u003cT\u003e(a: T[]): (b: T[]) =\u003e T[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.difference\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { includes } from './includes.js'\nimport { uniq } from './uniq.js'\n\nexport function difference(a, b){\n  if (arguments.length === 1) return _b =\u003e difference(a, _b)\n\n  return uniq(a).filter(aInstance =\u003e !includes(aInstance, 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 { difference as differenceRamda } from 'ramda'\n\nimport { difference } from './difference.js'\n\ntest('difference', () =\u003e {\n  const a = [ 1, 2, 3, 4 ]\n  const b = [ 3, 4, 5, 6 ]\n  expect(difference(a)(b)).toEqual([ 1, 2 ])\n\n  expect(difference([], [])).toEqual([])\n})\n\ntest('difference with objects', () =\u003e {\n  const a = [ { id : 1 }, { id : 2 }, { id : 3 }, { id : 4 } ]\n  const b = [ { id : 3 }, { id : 4 }, { id : 5 }, { id : 6 } ]\n  expect(difference(a, b)).toEqual([ { id : 1 }, { id : 2 } ])\n})\n\ntest('no duplicates in first list', () =\u003e {\n  const M2 = [ 1, 2, 3, 4, 1, 2, 3, 4 ]\n  const N2 = [ 3, 3, 4, 4, 5, 5, 6, 6 ]\n  expect(difference(M2, N2)).toEqual([ 1, 2 ])\n})\n\ntest('should use R.equals', () =\u003e {\n  expect(difference([ 1 ], [ 1 ])).toHaveLength(0)\n  expect(differenceRamda([ NaN ], [ NaN ])).toHaveLength(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 {difference} from 'rambda'\n\nconst list1 = [1, 2, 3]\nconst list2 = [1, 2, 4]\n\ndescribe('R.difference', () =\u003e {\n  it('happy', () =\u003e {\n    const result = difference(list1, list2)\n\n    result // $ExpectType number[]\n  })\n  it('curried', () =\u003e {\n    const result = difference(list1)(list2)\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)](#difference)\n\n### differenceWith\n\n```typescript\n\ndifferenceWith\u003cT1, T2\u003e(\n  pred: (a: T1, b: T2) =\u003e boolean,\n  list1: T1[],\n  list2: T2[],\n): T1[]\n```\n\n```javascript\nconst result = R.differenceWith(\n  (a, b) =\u003e a.x === b.x,\n  [{x: 1}, {x: 2}],\n  [{x: 1}, {x: 3}]\n)\n// =\u003e [{x: 2}]\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.differenceWith(%0A%20%20(a%2C%20b)%20%3D%3E%20a.x%20%3D%3D%3D%20b.x%2C%0A%20%20%5B%7Bx%3A%201%7D%2C%20%7Bx%3A%202%7D%5D%2C%0A%20%20%5B%7Bx%3A%201%7D%2C%20%7Bx%3A%203%7D%5D%0A)%0A%2F%2F%20%3D%3E%20%5B%7Bx%3A%202%7D%5D\"\u003eTry this \u003cstrong\u003eR.differenceWith\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ndifferenceWith\u003cT1, T2\u003e(\n  pred: (a: T1, b: T2) =\u003e boolean,\n  list1: T1[],\n  list2: T2[],\n): T1[];\ndifferenceWith\u003cT1, T2\u003e(\n  pred: (a: T1, b: T2) =\u003e boolean,\n): (list1: T1[], list2: T2[]) =\u003e T1[];\ndifferenceWith\u003cT1, T2\u003e(\n  pred: (a: T1, b: T2) =\u003e boolean,\n  list1: T1[],\n): (list2: T2[]) =\u003e T1[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.differenceWith\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { curry } from './curry.js'\nimport { _indexOf } from './equals.js'\n\nexport function differenceWithFn(\n  fn, a, b\n){\n  const willReturn = []\n  const [ first, second ] = a.length \u003e b.length ? [ a, b ] : [ b, a ]\n\n  first.forEach(item =\u003e {\n    const hasItem = second.some(secondItem =\u003e fn(item, secondItem))\n    if (!hasItem \u0026\u0026 _indexOf(item, willReturn) === -1){\n      willReturn.push(item)\n    }\n  })\n\n  return willReturn\n}\n\nexport const differenceWith = curry(differenceWithFn)\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 { differenceWith } from './differenceWith.js'\n\ntest('happy', () =\u003e {\n  const foo = [ { a : 1 }, { a : 2 }, { a : 3 } ]\n  const bar = [ { a : 3 }, { a : 4 } ]\n  const fn = function (r, s){\n    return r.a === s.a\n  }\n  const result = differenceWith(\n    fn, foo, bar\n  )\n  expect(result).toEqual([ { a : 1 }, { a : 2 } ])\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#differenceWith)\n\n### dissoc\n\nIt returns a new object that does not contain property `prop`.\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.dissoc('b'%2C%20%7Ba%3A%201%2C%20b%3A%202%2C%20c%3A%203%7D)%0A%2F%2F%20%3D%3E%20%7Ba%3A%201%2C%20c%3A%203%7D\"\u003eTry this \u003cstrong\u003eR.dissoc\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#dissoc)\n\n### dissocPath\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.dissocPath(%5B'a'%2C%20'b'%5D%2C%20%7Ba%3A%20%7Bb%3A%201%2C%20c%3A%202%7D%7D)%0A%2F%2F%20%3D%3E%20%7Ba%3A%20%7Bc%3A%202%7D%7D\"\u003eTry this \u003cstrong\u003eR.dissocPath\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#dissocPath)\n\n### divide\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.divide(71%2C%20100)%20%2F%2F%20%3D%3E%200.71\"\u003eTry this \u003cstrong\u003eR.divide\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#divide)\n\n### drop\n\n```typescript\n\ndrop\u003cT\u003e(howMany: number, input: T[]): T[]\n```\n\nIt returns `howMany` items dropped from beginning of list or string `input`.\n\n```javascript\nR.drop(2, ['foo', 'bar', 'baz']) // =\u003e ['baz']\nR.drop(2, 'foobar')  // =\u003e 'obar'\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?R.drop(2%2C%20%5B'foo'%2C%20'bar'%2C%20'baz'%5D)%20%2F%2F%20%3D%3E%20%5B'baz'%5D%0Aconst%20result%20%3D%20R.drop(2%2C%20'foobar')%20%20%2F%2F%20%3D%3E%20'obar'\"\u003eTry this \u003cstrong\u003eR.drop\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ndrop\u003cT\u003e(howMany: number, input: T[]): T[];\ndrop(howMany: number, input: string): string;\ndrop\u003cT\u003e(howMany: number): {\n  \u003cT\u003e(input: T[]): T[];\n  (input: string): string;\n};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.drop\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function drop(howManyToDrop, listOrString){\n  if (arguments.length === 1) return _list =\u003e drop(howManyToDrop, _list)\n\n  return listOrString.slice(howManyToDrop \u003e 0 ? howManyToDrop : 0)\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'\n\nimport { drop } from './drop.js'\n\ntest('with array', () =\u003e {\n  expect(drop(2)([ 'foo', 'bar', 'baz' ])).toEqual([ 'baz' ])\n  expect(drop(3, [ 'foo', 'bar', 'baz' ])).toEqual([])\n  expect(drop(4, [ 'foo', 'bar', 'baz' ])).toEqual([])\n})\n\ntest('with string', () =\u003e {\n  expect(drop(3, 'rambda')).toBe('bda')\n})\n\ntest('with non-positive count', () =\u003e {\n  expect(drop(0, [ 1, 2, 3 ])).toEqual([ 1, 2, 3 ])\n  expect(drop(-1, [ 1, 2, 3 ])).toEqual([ 1, 2, 3 ])\n  expect(drop(-Infinity, [ 1, 2, 3 ])).toEqual([ 1, 2, 3 ])\n})\n\ntest('should return copy', () =\u003e {\n  const xs = [ 1, 2, 3 ]\n\n  assert.notStrictEqual(drop(0, xs), xs)\n  assert.notStrictEqual(drop(-1, xs), xs)\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 {drop} from 'rambda'\n\nconst list = [1, 2, 3, 4]\nconst str = 'foobar'\nconst howMany = 2\n\ndescribe('R.drop - array', () =\u003e {\n  it('happy', () =\u003e {\n    const result = drop(howMany, list)\n    result // $ExpectType number[]\n  })\n  it('curried', () =\u003e {\n    const result = drop(howMany)(list)\n    result // $ExpectType number[]\n  })\n})\n\ndescribe('R.drop - string', () =\u003e {\n  it('happy', () =\u003e {\n    const result = drop(howMany, str)\n    result // $ExpectType string\n  })\n  it('curried', () =\u003e {\n    const result = drop(howMany)(str)\n    result // $ExpectType string\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#drop)\n\n### dropLast\n\n```typescript\n\ndropLast\u003cT\u003e(howMany: number, input: T[]): T[]\n```\n\nIt returns `howMany` items dropped from the end of list or string `input`.\n\n```javascript\nR.dropLast(2, ['foo', 'bar', 'baz']) // =\u003e ['foo']\nR.dropLast(2, 'foobar')  // =\u003e 'foob'\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?R.dropLast(2%2C%20%5B'foo'%2C%20'bar'%2C%20'baz'%5D)%20%2F%2F%20%3D%3E%20%5B'foo'%5D%0Aconst%20result%20%3D%20R.dropLast(2%2C%20'foobar')%20%20%2F%2F%20%3D%3E%20'foob'\"\u003eTry this \u003cstrong\u003eR.dropLast\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ndropLast\u003cT\u003e(howMany: number, input: T[]): T[];\ndropLast(howMany: number, input: string): string;\ndropLast\u003cT\u003e(howMany: number): {\n  \u003cT\u003e(input: T[]): T[];\n  (input: string): string;\n};\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.dropLast\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function dropLast(howManyToDrop, listOrString){\n  if (arguments.length === 1){\n    return _listOrString =\u003e dropLast(howManyToDrop, _listOrString)\n  }\n\n  return howManyToDrop \u003e 0 ?\n    listOrString.slice(0, -howManyToDrop) :\n    listOrString.slice()\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'\n\nimport { dropLast } from './dropLast.js'\n\ntest('with array', () =\u003e {\n  expect(dropLast(2)([ 'foo', 'bar', 'baz' ])).toEqual([ 'foo' ])\n  expect(dropLast(3, [ 'foo', 'bar', 'baz' ])).toEqual([])\n  expect(dropLast(4, [ 'foo', 'bar', 'baz' ])).toEqual([])\n})\n\ntest('with string', () =\u003e {\n  expect(dropLast(3, 'rambda')).toBe('ram')\n})\n\ntest('with non-positive count', () =\u003e {\n  expect(dropLast(0, [ 1, 2, 3 ])).toEqual([ 1, 2, 3 ])\n  expect(dropLast(-1, [ 1, 2, 3 ])).toEqual([ 1, 2, 3 ])\n  expect(dropLast(-Infinity, [ 1, 2, 3 ])).toEqual([ 1, 2, 3 ])\n})\n\ntest('should return copy', () =\u003e {\n  const xs = [ 1, 2, 3 ]\n\n  assert.notStrictEqual(dropLast(0, xs), xs)\n  assert.notStrictEqual(dropLast(-1, xs), xs)\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 {dropLast} from 'rambda'\n\nconst list = [1, 2, 3, 4]\nconst str = 'foobar'\nconst howMany = 2\n\ndescribe('R.dropLast - array', () =\u003e {\n  it('happy', () =\u003e {\n    const result = dropLast(howMany, list)\n    result // $ExpectType number[]\n  })\n  it('curried', () =\u003e {\n    const result = dropLast(howMany)(list)\n    result // $ExpectType number[]\n  })\n})\n\ndescribe('R.dropLast - string', () =\u003e {\n  it('happy', () =\u003e {\n    const result = dropLast(howMany, str)\n    result // $ExpectType string\n  })\n  it('curried', () =\u003e {\n    const result = dropLast(howMany)(str)\n    result // $ExpectType string\n  })\n})\n```\n\n\u003c/details\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#dropLast)\n\n### dropLastWhile\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20list%20%3D%20%5B1%2C%202%2C%203%2C%204%2C%205%5D%3B%0Aconst%20predicate%20%3D%20x%20%3D%3E%20x%20%3E%3D%203%0A%0Aconst%20result%20%3D%20dropLastWhile(predicate%2C%20list)%3B%0A%2F%2F%20%3D%3E%20%5B1%2C%202%5D\"\u003eTry this \u003cstrong\u003eR.dropLastWhile\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#dropLastWhile)\n\n### dropRepeats\n\n```typescript\n\ndropRepeats\u003cT\u003e(list: T[]): T[]\n```\n\nIt removes any successive duplicates according to `R.equals`.\n\n```javascript\nconst result = R.dropRepeats([\n  1, \n  1, \n  {a: 1}, \n  {a:1}, \n  1\n])\n// =\u003e [1, {a: 1}, 1]\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.dropRepeats(%5B%0A%20%201%2C%20%0A%20%201%2C%20%0A%20%20%7Ba%3A%201%7D%2C%20%0A%20%20%7Ba%3A1%7D%2C%20%0A%20%201%0A%5D)%0A%2F%2F%20%3D%3E%20%5B1%2C%20%7Ba%3A%201%7D%2C%201%5D\"\u003eTry this \u003cstrong\u003eR.dropRepeats\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\ndropRepeats\u003cT\u003e(list: T[]): T[];\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.dropRepeats\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nimport { isArray } from './_internals/isArray.js'\nimport { equals } from './equals.js'\n\nexport function dropRepeats(list){\n  if (!isArray(list)){\n    throw new Error(`${ list } is not a list`)\n  }\n\n  const toReturn = []\n\n  list.reduce((prev, current) =\u003e {\n    if (!equals(prev, current)){\n      toReturn.push(current)\n    }\n\n    return current\n  }, undefined)\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 { dropRepeats as dropRepeatsRamda } from 'ramda'\n\nimport { compareCombinations } from './_internals/testUtils.js'\nimport { add } from './add.js'\nimport { dropRepeats } from './dropRepeats.js'\n\nconst list = [ 1, 2, 2, 2, 3, 4, 4, 5, 5, 3, 2, 2, { a : 1 }, { a : 1 } ]\nconst listClean = [ 1, 2, 3, 4, 5, 3, 2, { a : 1 } ]\n\ntest('happy', () =\u003e {\n  const result = dropRepeats(list)\n  expect(result).toEqual(listClean)\n})\n\nconst possibleLists = [\n  [ add(1), async () =\u003e {}, [ 1 ], [ 1 ], [ 2 ], [ 2 ] ],\n  [ add(1), add(1), add(2) ],\n  [],\n  1,\n  /foo/g,\n  Promise.resolve(1),\n]\n\ndescribe('brute force', () =\u003e {\n  compareCombinations({\n    firstInput : possibleLists,\n    callback   : errorsCounters =\u003e {\n      expect(errorsCounters).toMatchInlineSnapshot(`\n        {\n          \"ERRORS_MESSAGE_MISMATCH\": 0,\n          \"ERRORS_TYPE_MISMATCH\": 0,\n          \"RESULTS_MISMATCH\": 1,\n          \"SHOULD_NOT_THROW\": 3,\n          \"SHOULD_THROW\": 0,\n          \"TOTAL_TESTS\": 6,\n        }\n      `)\n    },\n    fn      : dropRepeats,\n    fnRamda : dropRepeatsRamda,\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 {dropRepeats} from 'rambda'\n\ndescribe('R.dropRepeats', () =\u003e {\n  it('happy', () =\u003e {\n    const result = dropRepeats([1, 2, 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)](#dropRepeats)\n\n### dropRepeatsBy\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20result%20%3D%20R.dropRepeatsBy(%0A%20%20Math.abs%2C%0A%20%20%5B1%2C%20-1%2C%202%2C%203%2C%20-3%5D%0A)%0A%2F%2F%20%3D%3E%20%5B1%2C%202%2C%203%5D\"\u003eTry this \u003cstrong\u003eR.dropRepeatsBy\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#dropRepeatsBy)\n\n### dropRepeatsWith\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20list%20%3D%20%5B%7Ba%3A1%2Cb%3A2%7D%2C%20%7Ba%3A1%2Cb%3A3%7D%2C%20%7Ba%3A2%2C%20b%3A4%7D%5D%0Aconst%20result%20%3D%20R.dropRepeatsWith(R.prop('a')%2C%20list)%0A%0A%2F%2F%20%3D%3E%20%5B%7Ba%3A1%2Cb%3A2%7D%2C%20%7Ba%3A2%2C%20b%3A4%7D%5D\"\u003eTry this \u003cstrong\u003eR.dropRepeatsWith\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#dropRepeatsWith)\n\n### dropWhile\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20list%20%3D%20%5B1%2C%202%2C%203%2C%204%5D%0Aconst%20predicate%20%3D%20x%20%3D%3E%20x%20%3C%203%0Aconst%20result%20%3D%20R.dropWhile(predicate%2C%20list)%0A%2F%2F%20%3D%3E%20%5B3%2C%204%5D\"\u003eTry this \u003cstrong\u003eR.dropWhile\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#dropWhile)\n\n### either\n\n```typescript\n\neither(firstPredicate: Pred, secondPredicate: Pred): Pred\n```\n\nIt returns a new `predicate` function from `firstPredicate` and `secondPredicate` inputs.\n\nThis `predicate` function will return `true`, if any of the two input predicates return `true`.\n\n```javascript\nconst firstPredicate = x =\u003e x \u003e 10\nconst secondPredicate = x =\u003e x % 2 === 0\nconst predicate = R.either(firstPredicate, secondPredicate)\n\nconst result = [\n  predicate(15),\n  predicate(8),\n  predicate(7),\n]\n// =\u003e [true, true, false]\n```\n\n\u003ca title=\"redirect to Rambda Repl site\" href=\"https://rambda.now.sh?const%20firstPredicate%20%3D%20x%20%3D%3E%20x%20%3E%2010%0Aconst%20secondPredicate%20%3D%20x%20%3D%3E%20x%20%25%202%20%3D%3D%3D%200%0Aconst%20predicate%20%3D%20R.either(firstPredicate%2C%20secondPredicate)%0A%0Aconst%20result%20%3D%20%5B%0A%20%20predicate(15)%2C%0A%20%20predicate(8)%2C%0A%20%20predicate(7)%2C%0A%5D%0A%2F%2F%20%3D%3E%20%5Btrue%2C%20true%2C%20false%5D\"\u003eTry this \u003cstrong\u003eR.either\u003c/strong\u003e example in Rambda REPL\u003c/a\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003eAll TypeScript definitions\u003c/summary\u003e\n\n```typescript\neither(firstPredicate: Pred, secondPredicate: Pred): Pred;\neither\u003cT\u003e(firstPredicate: Predicate\u003cT\u003e, secondPredicate: Predicate\u003cT\u003e): Predicate\u003cT\u003e;\neither\u003cT\u003e(firstPredicate: Predicate\u003cT\u003e): (secondPredicate: Predicate\u003cT\u003e) =\u003e Predicate\u003cT\u003e;\neither(firstPredicate: Pred): (secondPredicate: Pred) =\u003e Pred;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cstrong\u003eR.either\u003c/strong\u003e source\u003c/summary\u003e\n\n```javascript\nexport function either(firstPredicate, secondPredicate){\n  if (arguments.length === 1){\n    return _secondPredicate =\u003e either(firstPredicate, _secondPredicate)\n  }\n\n  return (...input) =\u003e\n    Boolean(firstPredicate(...input) || secondPredicate(...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 { either } from './either.js'\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 ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselfrefactor%2Frambdax","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fselfrefactor%2Frambdax","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselfrefactor%2Frambdax/lists"}