https://github.com/selfrefactor/rambda
Typescript focused FP library similar to Remeda and Rambda
https://github.com/selfrefactor/rambda
fp functional functional-programming functions lodash ramda typescript utility utils
Last synced: 15 days ago
JSON representation
Typescript focused FP library similar to Remeda and Rambda
- Host: GitHub
- URL: https://github.com/selfrefactor/rambda
- Owner: selfrefactor
- License: mit
- Created: 2017-01-15T13:50:45.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2025-04-17T07:16:10.000Z (21 days ago)
- Last Synced: 2025-04-17T19:06:49.135Z (20 days ago)
- Topics: fp, functional, functional-programming, functions, lodash, ramda, typescript, utility, utils
- Language: JavaScript
- Homepage: https://selfrefactor.github.io/rambda/
- Size: 14.1 MB
- Stars: 1,703
- Watchers: 15
- Forks: 88
- Open Issues: 1
-
Metadata Files:
- Readme: .github/README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
- awesome-tiny-js - rambda - 187 tree-shakable helpers [(list).](https://bundlephobia.com/package/rambda) (Generic Utilities / Reactive Programming)
- awesome-fp-js - Rambda - A faster alternative to Ramda in under 10kB. (Libraries)
- fucking-awesome-fp-js - Rambda - A faster alternative to Ramda in under 10kB. (Libraries)
- fucking-awesome-fp-js - Rambda - A faster alternative to Ramda in under 10kB. (Libraries)
README
# Rambda
`Rambda` is TypeScript-focused utility library similar to `Remeda` and `Lodash`.
Initially it started as faster alternative to functional programming library `Ramda`, but in order to address many TypeScript issues, now `Rambda` takes a separate path. - [Documentation](https://selfrefactor.github.io/rambda/#/)


[](https://packagephobia.com/result?p=rambda)
[](https://github.com/selfrefactor/rambda/pulls)
[](https://github.com/selfrefactor/rambda/graphs/contributors)## ❯ Example use
```javascript
import { pipe, map, filter } from 'rambda'const result = pipe(
[1, 2, 3, 4],
filter(x => x > 2),
map(x => x * 2),
)
// => [6, 8]
```You can test this example in Rambda's REPL
* [API](#api)
* [Changelog](#-changelog)[](#-example-use)
## ❯ Rambda's features
## ❯ Goals
### Typescript focus
Mixing `Functional Programming` and `TypeScript` is not easy.
One way to solve this is to focus what can be actually achieved and refrain from what is not possible.
### `R.pipe` as the main way to use Rambda
- All methods are meant to be used as part of `R.pipe` chain
- This is the main purpose of functional programming, i.e. to pass data through a chain of functions.
- Having `R.pipe(input, ...fns)` helps TypeScript to infer the types of the input and the output.
Here is one example why `R.pipe` is better than `Ramda.pipe`:
```ts
const list = [1, 2, 3];it('within pipe', () => {
const result = pipe(
list,
filter((x) => {
x; // $ExpectType number
return x > 1;
}),
);
result; // $ExpectType number[]
});
it('within Ramda.pipe requires explicit types', () => {
Ramda.pipe(
(x) => x,
filter((x) => {
x; // $ExpectType number
return x > 1;
}),
filter((x: number) => {
x; // $ExpectType number
return x > 1;
}),
)(list);
});
```### Keep only the most useful methods
The idea is to give `TypeScript` users only the most useful methods and let them implement the rest. No magic logic methods that are hard to remember. You shouldn't need to read the documentation to understand what a method does. Its name and signature should be enough.
- Methods that are simply to remember only by its name. Complex logic shouldn't be part of utility library, but part of your codebase.
- Keep only methods which are both useful and which behaviour is obvious from its name. For example, `R.innerJoin` is kept, but `R.identical`, `R.move` is removed. Methods such as `R.toLower`, `R.length` provide little value. Such method are omitted from Rambda on purpose.
- Some generic methods such as `curry` and `assoc` is not easy to be expressed in TypeScript. For this reason `Rambda` omits such methods.
- No `R.cond` or `R.ifElse` as they make the chain less readable.
- No `R.length` as it adds very little value.
- No `R.difference` as user must remember the order of the inputs, i.e. which is compared to and which is compared against.
### One way to use each method
Because of the focus on `R.pipe`, there is only one way to use each method. This helps with testing and also with TypeScript definitions.
- All methods that 2 inputs, will have to be called with `R.methodName(input1)(input2)`
- All methods that 3 inputs, will have to be called with `R.methodName(input1, input2)(input3)`### Immutable TS definitions
You can use immutable version of Rambda definitions, which is linted with ESLint `functional/prefer-readonly-type` plugin.
```
import {filter} from 'rambda/immutable'
```### Deno support
```
import * as R from "https://deno.land/x/rambda/mod.ts";R.filter(x => x > 1)([1, 2, 3])
```### Dot notation for `R.path`
Standard usage of `R.path` is `R.path(['a', 'b'])({a: {b: 1} })`.
In **Rambda** you have the choice to use dot notation(which is arguably more readable):
```
R.path('a.b')({a: {b: 1} })
```Please note that since path input is turned into array, i.e. if you want `R.path(['a','1', 'b'])({a: {'1': {b: 2}}})` to return `2`, you will have to pass array path, not string path. If you pass `a.1.b`, it will turn path input to `['a', 1, 'b']`.
### Comma notation for `R.pick` and `R.omit`
Similar to dot notation, but the separator is comma(`,`) instead of dot(`.`).
```
R.pick('a,b', {a: 1 , b: 2, c: 3} })
// No space allowed between properties
```### Fast performance compared to Ramda
Since `Rambda` methods doesn't use so many internals, it is faster than `Ramda`.
Prior to version `10`, benchmark summary was included, but now the main selling point is the TypeScript focus, not performance so this is no longer included.### Differences between Rambda and Ramda
Up until version `9.4.2`, the aim of Rambda was to match as much as possible the Ramda API.
Documentation site of `Rambda` version `9.4.2` is available [here](https://selfrefactor.github.io/rambda-v9/).
From version `10.0.0` onwards, Rambda will start to diverge from Ramda in order to address some of the issues that Ramda has.
Ramda issues
-- Typescript support - this is the main reason for the divergence. Most of design decisions in Rambda are made with Typescript in mind.
-- Methods that imply side-effect, which is not FP oriented, e.g. `R.forEach`.
-- Naming of methods that doesn't match developer's expectation, such as `R.chain`, which should be called `flatMap`.
-- Naming of methods is sometimes too generic to be remembered such as `R.update`, `R.modify`, `R.where`.
-- Methods that are already present in standard JavaScript, such as `R.toLower`, `R.length`.
-- `R.compose` doesn't have the best possible TypeScript support.
[](#-rambdas-features)
## API
### addProp
```typescript
addProp(
prop: P,
value: V
): (obj: T) => MergeTypes>
```It adds new key-value pair to the object.
```javascript
const result = R.pipe(
{ a: 1, b: 'foo' },
R.addProp('c', 3)
)
// => { a: 1, b: 'foo', c: 3 }
```Try this R.addProp example in Rambda REPL
All TypeScript definitions
```typescript
addProp(
prop: P,
value: V
): (obj: T) => MergeTypes>;
```R.addProp source
```javascript
export function addProp(key, value) {
return obj => ({ ...obj, [key]: value })
}
```Tests
```javascript
import { addProp } from "./addProp.js"test('happy', () => {
const result = addProp('a', 1)({ b: 2 })
const expected = { a: 1, b: 2 }expect(result).toEqual(expected)
})
```TypeScript test
```typescript
import { addProp, pipe } from 'rambda'it('R.addProp', () => {
const result = pipe({ a: 1, b: 'foo' }, addProp('c', 3))
result.a // $ExpectType number
result.b // $ExpectType string
result.c // $ExpectType number
})
```[](#addProp)
### all
```typescript
all(predicate: (x: T) => boolean): (list: T[]) => boolean
```It returns `true`, if all members of array `list` returns `true`, when applied as argument to `predicate` function.
```javascript
const list = [ 0, 1, 2, 3, 4 ]
const predicate = x => x > -1const result = R.pipe(
list,
R.all(predicate)
) // => true
```Try this R.all example in Rambda REPL
All TypeScript definitions
```typescript
all(predicate: (x: T) => boolean): (list: T[]) => boolean;
```R.all source
```javascript
export function all(predicate) {
return list => {
for (let i = 0; i < list.length; i++) {
if (!predicate(list[i])) {
return false
}
}return true
}
}
```Tests
```javascript
import { all } from './all.js'const list = [0, 1, 2, 3, 4]
test('when true', () => {
const fn = x => x > -1expect(all(fn)(list)).toBeTruthy()
})test('when false', () => {
const fn = x => x > 2expect(all(fn)(list)).toBeFalsy()
})
```TypeScript test
```typescript
import * as R from 'rambda'describe('all', () => {
it('happy', () => {
const result = R.pipe(
[1, 2, 3],
R.all(x => {
x // $ExpectType number
return x > 0
}),
)
result // $ExpectType boolean
})
})
```[](#all)
### allPass
```typescript
allPass boolean>(predicates: readonly F[]): F
```It returns `true`, if all functions of `predicates` return `true`, when `input` is their argument.
```javascript
const list = [[1, 2, 3, 4], [3, 4, 5]]
const result = R.pipe(
list,
R.filter(R.allPass([R.includes(2), R.includes(3)]))
) // => [[1, 2, 3, 4]]
```Try this R.allPass example in Rambda REPL
All TypeScript definitions
```typescript
allPass boolean>(predicates: readonly F[]): F;
```R.allPass source
```javascript
export function allPass(predicates) {
return input => {
let counter = 0
while (counter < predicates.length) {
if (!predicates[counter](input)) {
return false
}
counter++
}return true
}
}
```Tests
```javascript
import { allPass } from './allPass.js'
import { filter } from './filter.js'
import { includes } from './includes.js'
import { pipe } from './pipe.js'const list = [
[1, 2, 3, 4],
[3, 4, 5],
]
test('happy', () => {
const result = pipe(list, filter(allPass([includes(2), includes(3)])))
expect(result).toEqual([[1, 2, 3, 4]])
})test('when returns false', () => {
const result = pipe(list, filter(allPass([includes(12), includes(31)])))
expect(result).toEqual([])
})
```TypeScript test
```typescript
import * as R from 'rambda'describe('allPass', () => {
it('happy', () => {
const list = [
[1, 2, 3, 4],
[3, 4, 5],
]
const result = R.pipe(list, R.map(R.allPass([R.includes(3), R.includes(4)])))
result // $ExpectType boolean[]
})
})
```[](#allPass)
### any
```typescript
any(predicate: (x: T) => boolean): (list: T[]) => boolean
```It returns `true`, if at least one member of `list` returns true, when passed to a `predicate` function.
```javascript
const list = [1, 2, 3]
const predicate = x => x * x > 8
R.any(fn)(list)
// => true
```Try this R.any example in Rambda REPL
All TypeScript definitions
```typescript
any(predicate: (x: T) => boolean): (list: T[]) => boolean;
```R.any source
```javascript
export function any(predicate) {
return list => {
let counter = 0
while (counter < list.length) {
if (predicate(list[counter], counter)) {
return true
}
counter++
}return false
}
}
```Tests
```javascript
import { any } from './any.js'const list = [1, 2, 3]
test('happy', () => {
expect(any(x => x > 2)(list)).toBeTruthy()
})
```TypeScript test
```typescript
import { any, pipe } from 'rambda'it('R.any', () => {
const result = pipe(
[1, 2, 3],
any(x => {
x // $ExpectType number
return x > 2
}),
)
result // $ExpectType boolean
})
```[](#any)
### anyPass
```typescript
anyPass(
predicates: [(a: T) => a is TF1, (a: T) => a is TF2],
): (a: T) => a is TF1 | TF2
```It 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`.
> :boom: Function accepts only one input, but in Ramda it accepts indefinite number of arguments.
```javascript
const isBig = x => x > 20
const isOdd = x => x % 2 === 1
const input = 11const fn = R.anyPass(
[isBig, isOdd]
)const result = fn(input)
// => true
```Try this R.anyPass example in Rambda REPL
All TypeScript definitions
```typescript
anyPass(
predicates: [(a: T) => a is TF1, (a: T) => a is TF2],
): (a: T) => a is TF1 | TF2;
anyPass(
predicates: [(a: T) => a is TF1, (a: T) => a is TF2, (a: T) => a is TF3],
): (a: T) => a is TF1 | TF2 | TF3;
anyPass(
predicates: [(a: T) => a is TF1, (a: T) => a is TF2, (a: T) => a is TF3],
): (a: T) => a is TF1 | TF2 | TF3;
anyPass(
predicates: [(a: T) => a is TF1, (a: T) => a is TF2, (a: T) => a is TF3, (a: T) => a is TF4],
): (a: T) => a is TF1 | TF2 | TF3 | TF4;
anyPass(
predicates: [
(a: T) => a is TF1,
(a: T) => a is TF2,
(a: T) => a is TF3,
(a: T) => a is TF4,
(a: T) => a is TF5
],
): (a: T) => a is TF1 | TF2 | TF3 | TF4 | TF5;
anyPass(
predicates: [
(a: T) => a is TF1,
(a: T) => a is TF2,
(a: T) => a is TF3,
(a: T) => a is TF4,
(a: T) => a is TF5,
(a: T) => a is TF6
],
): (a: T) => a is TF1 | TF2 | TF3 | TF4 | TF5 | TF6;
anyPass boolean>(predicates: readonly F[]): F;
```R.anyPass source
```javascript
export function anyPass(predicates) {
return input => {
let counter = 0
while (counter < predicates.length) {
if (predicates[counter](input)) {
return true
}
counter++
}return false
}
}
```Tests
```javascript
import { anyPass } from './anyPass.js'test('happy', () => {
const rules = [x => typeof x === 'string', x => x > 10]
const predicate = anyPass(rules)
expect(predicate('foo')).toBeTruthy()
expect(predicate(6)).toBeFalsy()
})test('happy', () => {
const rules = [x => typeof x === 'string', x => x > 10]expect(anyPass(rules)(11)).toBeTruthy()
expect(anyPass(rules)(undefined)).toBeFalsy()
})const obj = {
a: 1,
b: 2,
}test('when returns true', () => {
const conditionArr = [val => val.a === 1, val => val.a === 2]expect(anyPass(conditionArr)(obj)).toBeTruthy()
})test('when returns false', () => {
const conditionArr = [val => val.a === 2, val => val.b === 3]expect(anyPass(conditionArr)(obj)).toBeFalsy()
})test('with empty predicates list', () => {
expect(anyPass([])(3)).toBeFalsy()
})
```TypeScript test
```typescript
import { anyPass, filter } from 'rambda'describe('anyPass', () => {
it('issue #604', () => {
const plusEq = (w: number, x: number, y: number, z: number) => w + x === y + z
const result = anyPass([plusEq])(3, 3, 3, 3)result // $ExpectType boolean
})
it('issue #642', () => {
const isGreater = (num: number) => num > 5
const pred = anyPass([isGreater])
const xs = [0, 1, 2, 3]const filtered1 = filter(pred)(xs)
filtered1 // $ExpectType number[]
const filtered2 = xs.filter(pred)
filtered2 // $ExpectType number[]
})
it('functions as a type guard', () => {
const isString = (x: unknown): x is string => typeof x === 'string'
const isNumber = (x: unknown): x is number => typeof x === 'number'
const isBoolean = (x: unknown): x is boolean => typeof x === 'boolean'const isStringNumberOrBoolean = anyPass([isString, isNumber, isBoolean])
const aValue: unknown = 1
if (isStringNumberOrBoolean(aValue)) {
aValue // $ExpectType string | number | boolean
}
})
})
```[](#anyPass)
### append
```typescript
append(el: T): (list: T[]) => T[]
```It adds element `x` at the end of `iterable`.
```javascript
const x = 'foo'const result = R.append(x, ['bar', 'baz'])
// => ['bar', 'baz', 'foo']
```Try this R.append example in Rambda REPL
All TypeScript definitions
```typescript
append(el: T): (list: T[]) => T[];
append(el: T): (list: readonly T[]) => T[];
```R.append source
```javascript
import { cloneList } from './_internals/cloneList.js'export function append(x) {
return list => {
const clone = cloneList(list)
clone.push(x)return clone
}
}
```Tests
```javascript
import { append } from './append.js'test('happy', () => {
expect(append('tests')(['write', 'more'])).toEqual(['write', 'more', 'tests'])
})test('append to empty array', () => {
expect(append('tests')([])).toEqual(['tests'])
})
```TypeScript test
```typescript
import { append, pipe, prepend } from 'rambda'const listOfNumbers = [1, 2, 3]
describe('R.append/R.prepend', () => {
it('happy', () => {
const result = pipe(listOfNumbers, append(4), prepend(0))
result // $ExpectType number[]
})
it('with object', () => {
const result = pipe([{ a: 1 }], append({ a: 10 }), prepend({ a: 20 }))
result // $ExpectType { a: number; }[]
})
})
```[](#append)
### ascend
Helper function to be used with `R.sort` to sort list in ascending order.
```javascript
const result = R.pipe(
[{a: 1}, {a: 2}, {a: 0}],
R.sort(R.ascend(R.prop('a')))
)
// => [{a: 0}, {a: 1}, {a: 2}]
```Try this R.ascend example in Rambda REPL
[](#ascend)
### checkObjectWithSpec
```typescript
checkObjectWithSpec(spec: T): (testObj: U) => boolean
```It returns `true` if all each property in `conditions` returns `true` when applied to corresponding property in `input` object.
```javascript
const condition = R.checkObjectWithSpec({
a : x => typeof x === "string",
b : x => x === 4
})
const input = {
a : "foo",
b : 4,
c : 11,
}const result = condition(input)
// => true
```Try this R.checkObjectWithSpec example in Rambda REPL
All TypeScript definitions
```typescript
checkObjectWithSpec(spec: T): (testObj: U) => boolean;
```R.checkObjectWithSpec source
```javascript
export function checkObjectWithSpec(conditions) {
return input => {
let shouldProceed = true
for (const prop in conditions) {
if (!shouldProceed) {
continue
}
const result = conditions[prop](input[prop])
if (shouldProceed && result === false) {
shouldProceed = false
}
}return shouldProceed
}
}
```Tests
```javascript
import { checkObjectWithSpec } from './checkObjectWithSpec.js'
import { equals } from './equals.js'test('when true', () => {
const result = checkObjectWithSpec({
a: equals('foo'),
b: equals('bar'),
})({
a: 'foo',
b: 'bar',
x: 11,
y: 19,
})expect(result).toBeTruthy()
})test('when false | early exit', () => {
let counter = 0
const equalsFn = expected => input => {
counter++return input === expected
}
const predicate = checkObjectWithSpec({
a: equalsFn('foo'),
b: equalsFn('baz'),
})
expect(
predicate({
a: 'notfoo',
b: 'notbar',
}),
).toBeFalsy()
expect(counter).toBe(1)
})
```TypeScript test
```typescript
import { checkObjectWithSpec, equals } from 'rambda'describe('R.checkObjectWithSpec', () => {
it('happy', () => {
const input = {
a: 'foo',
b: 'bar',
x: 11,
y: 19,
}
const conditions = {
a: equals('foo'),
b: equals('bar'),
}
const result = checkObjectWithSpec(conditions)(input)
result // $ExpectType boolean
})
})
```[](#checkObjectWithSpec)
### compact
```typescript
compact(list: T[]): Array>
```It removes `null` and `undefined` members from list or object input.
```javascript
const result = R.pipe(
{
a: [ undefined, '', 'a', 'b', 'c'],
b: [1,2, null, 0, undefined, 3],
c: { a: 1, b: 2, c: 0, d: undefined, e: null, f: false },
},
x => ({
a: R.compact(x.a),
b: R.compact(x.b),
c: R.compact(x.c)
})
)
// => { a: ['a', 'b', 'c'], b: [1, 2, 3], c: { a: 1, b: 2, c: 0, f: false } }
```Try this R.compact example in Rambda REPL
All TypeScript definitions
```typescript
compact(list: T[]): Array>;
compact(record: T): {
[K in keyof T as Exclude extends never
? never
: K
]: Exclude
};
```R.compact source
```javascript
import { isArray } from './_internals/isArray.js'
import { reject } from './reject.js'
import { rejectObject } from './rejectObject.js'const isNullOrUndefined = x => x === null || x === undefined
export function compact(input){
if(isArray(input)){
return reject(isNullOrUndefined)(input)
}
return rejectObject(isNullOrUndefined)(input)
}
```Tests
```javascript
import { compact } from './compact.js'
import { pipe } from './pipe.js'test('happy', () => {
const result = pipe(
{
a: [ undefined, 'a', 'b', 'c'],
b: [1,2, null, 0, undefined, 3],
c: { a: 1, b: 2, c: 0, d: undefined, e: null, f: false },
},
x => ({
a: compact(x.a),
b: compact(x.b),
c: compact(x.c)
})
)
expect(result.a).toEqual(['a', 'b', 'c'])
expect(result.b).toEqual([1,2,0,3])
expect(result.c).toEqual({ a: 1, b: 2,c:0, f: false })
})
```TypeScript test
```typescript
import { compact, pipe } from 'rambda'it('R.compact', () => {
let result = pipe(
{
a: [ undefined, '', 'a', 'b', 'c', null ],
b: [1,2, null, 0, undefined, 3],
c: { a: 1, b: 2, c: 0, d: undefined, e: null, f: false },
},
x => ({
a: compact(x.a),
b: compact(x.b),
c: compact(x.c)
})
)result.a // $ExpectType string[]
result.b // $ExpectType number[]
result.c // $ExpectType { a: number; b: number; c: number; f: boolean; }
})
```[](#compact)
### complement
It returns `inverted` version of `origin` function that accept `input` as argument.
The return value of `inverted` is the negative boolean value of `origin(input)`.
```javascript
const fn = x => x > 5
const inverted = complement(fn)const result = [
fn(7),
inverted(7)
] => [ true, false ]
```Try this R.complement example in Rambda REPL
[](#complement)
### concat
It returns a new string or array, which is the result of merging `x` and `y`.
```javascript
R.concat([1, 2])([3, 4]) // => [1, 2, 3, 4]
R.concat('foo')('bar') // => 'foobar'
```Try this R.concat example in Rambda REPL
[](#concat)
### count
It counts how many times `predicate` function returns `true`, when supplied with iteration of `list`.
```javascript
const list = [{a: 1}, 1, {a:2}]
const result = R.count(x => x.a !== undefined)(list)
// => 2
```Try this R.count example in Rambda REPL
[](#count)
### countBy
```typescript
countBy(fn: (x: T) => string | number): (list: T[]) => { [index: string]: number }
```It counts elements in a list after each instance of the input list is passed through `transformFn` function.
```javascript
const list = [ 'a', 'A', 'b', 'B', 'c', 'C' ]const result = countBy(x => x.toLowerCase())( list)
const expected = { a: 2, b: 2, c: 2 }
// => `result` is equal to `expected`
```Try this R.countBy example in Rambda REPL
All TypeScript definitions
```typescript
countBy(fn: (x: T) => string | number): (list: T[]) => { [index: string]: number };
```R.countBy source
```javascript
export function countBy(fn) {
return list => {
const willReturn = {}list.forEach(item => {
const key = fn(item)
if (!willReturn[key]) {
willReturn[key] = 1
} else {
willReturn[key]++
}
})return willReturn
}
}
```Tests
```javascript
import { countBy } from './countBy.js'const list = ['a', 'A', 'b', 'B', 'c', 'C']
test('happy', () => {
const result = countBy(x => x.toLowerCase())(list)
expect(result).toEqual({
a: 2,
b: 2,
c: 2,
})
})
```TypeScript test
```typescript
import { countBy, pipe } from 'rambda'const list = ['a', 'A', 'b', 'B', 'c', 'C']
it('R.countBy', () => {
const result = pipe(
list,
countBy(x => x.toLowerCase()),
)
result.a // $ExpectType number
result.foo // $ExpectType number
result // $ExpectType { [index: string]: number; }
})
```[](#countBy)
### createObjectFromKeys
```typescript
createObjectFromKeys(
fn: (key: K[number]) => V
): (keys: K) => { [P in K[number]]: V }
``````javascript
const result = R.createObjectFromKeys(
(x, index) => `${x}-${index}`
)(['a', 'b', 'c'])
// => {a: 'a-0', b: 'b-1', c: 'c-2'}
```Try this R.createObjectFromKeys example in Rambda REPL
All TypeScript definitions
```typescript
createObjectFromKeys(
fn: (key: K[number]) => V
): (keys: K) => { [P in K[number]]: V };
createObjectFromKeys(
fn: (key: K[number], index: number) => V
): (keys: K) => { [P in K[number]]: V };
```R.createObjectFromKeys source
```javascript
export function createObjectFromKeys(keys) {
return fn => {
const result = {}
keys.forEach((key, index) => {
result[key] = fn(key, index)
})return result
}
}
```Tests
```javascript
import { createObjectFromKeys } from './createObjectFromKeys.js'test('happy', () => {
const result = createObjectFromKeys(['a', 'b'])((key, index) => key.toUpperCase() + index)
const expected = { a: 'A0', b: 'B1' }expect(result).toEqual(expected)
})
```[](#createObjectFromKeys)
### defaultTo
```typescript
defaultTo(defaultValue: T): (input: unknown) => T
```It returns `defaultValue`, if all of `inputArguments` are `undefined`, `null` or `NaN`.
Else, it returns the first truthy `inputArguments` instance(from left to right).
> :boom: Typescript Note: Pass explicit type annotation when used with **R.pipe/R.compose** for better type inference
```javascript
R.defaultTo('foo')('bar') // => 'bar'
R.defaultTo('foo'))(undefined) // => 'foo'// Important - emtpy string is not falsy value
R.defaultTo('foo')('') // => 'foo'
```Try this R.defaultTo example in Rambda REPL
All TypeScript definitions
```typescript
defaultTo(defaultValue: T): (input: unknown) => T;
```R.defaultTo source
```javascript
function isFalsy(input) {
return input === undefined || input === null || Number.isNaN(input) === true
}export function defaultTo(defaultArgument, input) {
if (arguments.length === 1) {
return _input => defaultTo(defaultArgument, _input)
}return isFalsy(input) ? defaultArgument : input
}
```Tests
```javascript
import { defaultTo } from './defaultTo.js'test('with undefined', () => {
expect(defaultTo('foo')(undefined)).toBe('foo')
})test('with null', () => {
expect(defaultTo('foo')(null)).toBe('foo')
})test('with NaN', () => {
expect(defaultTo('foo')(Number.NaN)).toBe('foo')
})test('with empty string', () => {
expect(defaultTo('foo', '')).toBe('')
})test('with false', () => {
expect(defaultTo('foo', false)).toBeFalsy()
})test('when inputArgument passes initial check', () => {
expect(defaultTo('foo', 'bar')).toBe('bar')
})
```TypeScript test
```typescript
import { defaultTo, pipe } from 'rambda'describe('R.defaultTo', () => {
it('happy', () => {
const result = pipe('bar' as unknown, defaultTo('foo'))result // $ExpectType string
})
})
```[](#defaultTo)
### descend
Helper function to be used with `R.sort` to sort list in descending order.
```javascript
const result = R.pipe(
[{a: 1}, {a: 2}, {a: 0}],
R.sort(R.descend(R.prop('a')))
)
// => [{a: 2}, {a: 1}, {a: 0}]
```Try this R.descend example in Rambda REPL
[](#descend)
### drop
```typescript
drop(howMany: number): (list: T[]) => T[]
```It returns `howMany` items dropped from beginning of list.
```javascript
R.drop(2)(['foo', 'bar', 'baz']) // => ['baz']
```Try this R.drop example in Rambda REPL
All TypeScript definitions
```typescript
drop(howMany: number): (list: T[]) => T[];
```R.drop source
```javascript
export function drop(howManyToDrop, listOrString) {
if (arguments.length === 1) {
return _list => drop(howManyToDrop, _list)
}return listOrString.slice(howManyToDrop > 0 ? howManyToDrop : 0)
}
```Tests
```javascript
import assert from 'node:assert'import { drop } from './drop.js'
test('with array', () => {
expect(drop(2)(['foo', 'bar', 'baz'])).toEqual(['baz'])
expect(drop(3, ['foo', 'bar', 'baz'])).toEqual([])
expect(drop(4, ['foo', 'bar', 'baz'])).toEqual([])
})test('with string', () => {
expect(drop(3, 'rambda')).toBe('bda')
})test('with non-positive count', () => {
expect(drop(0, [1, 2, 3])).toEqual([1, 2, 3])
expect(drop(-1, [1, 2, 3])).toEqual([1, 2, 3])
expect(drop(Number.NEGATIVE_INFINITY, [1, 2, 3])).toEqual([1, 2, 3])
})test('should return copy', () => {
const xs = [1, 2, 3]assert.notStrictEqual(drop(0, xs), xs)
assert.notStrictEqual(drop(-1, xs), xs)
})
```TypeScript test
```typescript
import { drop, pipe } from 'rambda'it('R.drop', () => {
const result = pipe([1, 2, 3, 4], drop(2))
result // $ExpectType number[]
})
```[](#drop)
### dropLast
```typescript
dropLast(howMany: number): (list: T[]) => T[]
```It returns `howMany` items dropped from the end of list.
All TypeScript definitions
```typescript
dropLast(howMany: number): (list: T[]) => T[];
```R.dropLast source
```javascript
export function dropLast(numberItems) {
return list => (numberItems > 0 ? list.slice(0, -numberItems) : list.slice())
}
```Tests
```javascript
import { dropLast } from './dropLast.js'test('with array', () => {
expect(dropLast(2)(['foo', 'bar', 'baz'])).toEqual(['foo'])
expect(dropLast(3)(['foo', 'bar', 'baz'])).toEqual([])
expect(dropLast(4)(['foo', 'bar', 'baz'])).toEqual([])
})test('with non-positive count', () => {
expect(dropLast(0)([1, 2, 3])).toEqual([1, 2, 3])
expect(dropLast(-1)([1, 2, 3])).toEqual([1, 2, 3])
expect(dropLast(Number.NEGATIVE_INFINITY)([1, 2, 3])).toEqual([1, 2, 3])
})
```[](#dropLast)
### dropLastWhile
```javascript
const list = [1, 2, 3, 4, 5];
const predicate = x => x >= 3const result = dropLastWhile(predicate)(list);
// => [1, 2]
```Try this R.dropLastWhile example in Rambda REPL
[](#dropLastWhile)
### dropRepeatsBy
```javascript
const result = R.dropRepeatsBy(
Math.abs,
[1, -1, 2, 3, -3]
)
// => [1, 2, 3]
```Try this R.dropRepeatsBy example in Rambda REPL
[](#dropRepeatsBy)
### dropRepeatsWith
```javascript
const list = [{a:1,b:2}, {a:1,b:3}, {a:2, b:4}]
const result = R.dropRepeatsWith(R.prop('a'))(list)// => [{a:1,b:2}, {a:2, b:4}]
```Try this R.dropRepeatsWith example in Rambda REPL
[](#dropRepeatsWith)
### dropWhile
```javascript
const list = [1, 2, 3, 4]
const predicate = x => x < 3
const result = R.dropWhile(predicate)(list)
// => [3, 4]
```Try this R.dropWhile example in Rambda REPL
[](#dropWhile)
### eqBy
```javascript
const result = R.eqBy(Math.abs, 5)(-5)
// => true
```Try this R.eqBy example in Rambda REPL
[](#eqBy)
### eqProps
It returns `true` if property `prop` in `obj1` is equal to property `prop` in `obj2` according to `R.equals`.
```javascript
const obj1 = {a: 1, b:2}
const obj2 = {a: 1, b:3}
const result = R.eqProps('a', obj1)(obj2)
// => true
```Try this R.eqProps example in Rambda REPL
[](#eqProps)
### equals
```typescript
equals(x: T, y: T): boolean
```It deeply compares `x` and `y` and returns `true` if they are equal.
> :boom: It doesn't handle cyclical data structures and functions
```javascript
R.equals(
[1, {a:2}, [{b: 3}]],
[1, {a:2}, [{b: 3}]]
) // => true
```Try this R.equals example in Rambda REPL
All TypeScript definitions
```typescript
equals(x: T, y: T): boolean;
equals(x: T): (y: T) => boolean;
```R.equals source
```javascript
import { isArray } from './_internals/isArray.js'
import { type } from './type.js'export function _lastIndexOf(valueToFind, list) {
if (!isArray(list)) {
throw new Error(`Cannot read property 'indexOf' of ${list}`)
}const typeOfValue = type(valueToFind)
if (!['Array', 'NaN', 'Object', 'RegExp'].includes(typeOfValue)) {
return list.lastIndexOf(valueToFind)
}const { length } = list
let index = length
let foundIndex = -1while (--index > -1 && foundIndex === -1) {
if (equalsFn(list[index], valueToFind)) {
foundIndex = index
}
}return foundIndex
}export function _indexOf(valueToFind, list) {
if (!isArray(list)) {
throw new Error(`Cannot read property 'indexOf' of ${list}`)
}const typeOfValue = type(valueToFind)
if (!['Array', 'NaN', 'Object', 'RegExp'].includes(typeOfValue)) {
return list.indexOf(valueToFind)
}let index = -1
let foundIndex = -1
const { length } = listwhile (++index < length && foundIndex === -1) {
if (equalsFn(list[index], valueToFind)) {
foundIndex = index
}
}return foundIndex
}function _arrayFromIterator(iter) {
const list = []
let next
while (!(next = iter.next()).done) {
list.push(next.value)
}return list
}function _compareSets(a, b) {
if (a.size !== b.size) {
return false
}const aList = _arrayFromIterator(a.values())
const bList = _arrayFromIterator(b.values())const filtered = aList.filter(aInstance => _indexOf(aInstance, bList) === -1)
return filtered.length === 0
}function compareErrors(a, b) {
if (a.message !== b.message) {
return false
}
if (a.toString !== b.toString) {
return false
}return a.toString() === b.toString()
}function parseDate(maybeDate) {
if (!maybeDate.toDateString) {
return [false]
}return [true, maybeDate.getTime()]
}function parseRegex(maybeRegex) {
if (maybeRegex.constructor !== RegExp) {
return [false]
}return [true, maybeRegex.toString()]
}export function equalsFn(a, b) {
if (Object.is(a, b)) {
return true
}const aType = type(a)
if (aType !== type(b)) {
return false
}
if (aType === 'Function') {
return a.name === undefined ? false : a.name === b.name
}if (['NaN', 'Null', 'Undefined'].includes(aType)) {
return true
}if (['BigInt', 'Number'].includes(aType)) {
if (Object.is(-0, a) !== Object.is(-0, b)) {
return false
}return a.toString() === b.toString()
}if (['Boolean', 'String'].includes(aType)) {
return a.toString() === b.toString()
}if (aType === 'Array') {
const aClone = Array.from(a)
const bClone = Array.from(b)if (aClone.toString() !== bClone.toString()) {
return false
}let loopArrayFlag = true
aClone.forEach((aCloneInstance, aCloneIndex) => {
if (loopArrayFlag) {
if (
aCloneInstance !== bClone[aCloneIndex] &&
!equalsFn(aCloneInstance, bClone[aCloneIndex])
) {
loopArrayFlag = false
}
}
})return loopArrayFlag
}const aRegex = parseRegex(a)
const bRegex = parseRegex(b)if (aRegex[0]) {
return bRegex[0] ? aRegex[1] === bRegex[1] : false
}
if (bRegex[0]) {
return false
}const aDate = parseDate(a)
const bDate = parseDate(b)if (aDate[0]) {
return bDate[0] ? aDate[1] === bDate[1] : false
}
if (bDate[0]) {
return false
}if (a instanceof Error) {
if (!(b instanceof Error)) {
return false
}return compareErrors(a, b)
}if (aType === 'Set') {
return _compareSets(a, b)
}if (aType === 'Object') {
const aKeys = Object.keys(a)if (aKeys.length !== Object.keys(b).length) {
return false
}let loopObjectFlag = true
aKeys.forEach(aKeyInstance => {
if (loopObjectFlag) {
const aValue = a[aKeyInstance]
const bValue = b[aKeyInstance]if (aValue !== bValue && !equalsFn(aValue, bValue)) {
loopObjectFlag = false
}
}
})return loopObjectFlag
}return false
}
export function equals(a) {
return b => equalsFn(a, b)
}
```Tests
```javascript
import { equalsFn } from './equals.js'test('compare functions', () => {
function foo() {}
function bar() {}
const baz = () => {}const expectTrue = equalsFn(foo, foo)
const expectFalseFirst = equalsFn(foo, bar)
const expectFalseSecond = equalsFn(foo, baz)expect(expectTrue).toBeTruthy()
expect(expectFalseFirst).toBeFalsy()
expect(expectFalseSecond).toBeFalsy()
})test('with array of objects', () => {
const list1 = [{ a: 1 }, [{ b: 2 }]]
const list2 = [{ a: 1 }, [{ b: 2 }]]
const list3 = [{ a: 1 }, [{ b: 3 }]]expect(equalsFn(list1, list2)).toBeTruthy()
expect(equalsFn(list1, list3)).toBeFalsy()
})test('with regex', () => {
expect(equalsFn(/s/, /s/)).toBeTruthy()
expect(equalsFn(/s/, /d/)).toBeFalsy()
expect(equalsFn(/a/gi, /a/gi)).toBeTruthy()
expect(equalsFn(/a/gim, /a/gim)).toBeTruthy()
expect(equalsFn(/a/gi, /a/i)).toBeFalsy()
})test('not a number', () => {
expect(equalsFn([Number.NaN], [Number.NaN])).toBeTruthy()
})test('new number', () => {
expect(equalsFn(new Number(0), new Number(0))).toBeTruthy()
expect(equalsFn(new Number(0), new Number(1))).toBeFalsy()
expect(equalsFn(new Number(1), new Number(0))).toBeFalsy()
})test('new string', () => {
expect(equalsFn(new String(''), new String(''))).toBeTruthy()
expect(equalsFn(new String(''), new String('x'))).toBeFalsy()
expect(equalsFn(new String('x'), new String(''))).toBeFalsy()
expect(equalsFn(new String('foo'), new String('foo'))).toBeTruthy()
expect(equalsFn(new String('foo'), new String('bar'))).toBeFalsy()
expect(equalsFn(new String('bar'), new String('foo'))).toBeFalsy()
})test('new Boolean', () => {
expect(equalsFn(new Boolean(true), new Boolean(true))).toBeTruthy()
expect(equalsFn(new Boolean(false), new Boolean(false))).toBeTruthy()
expect(equalsFn(new Boolean(true), new Boolean(false))).toBeFalsy()
expect(equalsFn(new Boolean(false), new Boolean(true))).toBeFalsy()
})test('new Error', () => {
expect(equalsFn(new Error('XXX'), {})).toBeFalsy()
expect(equalsFn(new Error('XXX'), new TypeError('XXX'))).toBeFalsy()
expect(equalsFn(new Error('XXX'), new Error('YYY'))).toBeFalsy()
expect(equalsFn(new Error('XXX'), new Error('XXX'))).toBeTruthy()
expect(equalsFn(new Error('XXX'), new TypeError('YYY'))).toBeFalsy()
expect(equalsFn(new Error('XXX'), new Error('XXX'))).toBeTruthy()
})test('with dates', () => {
expect(equalsFn(new Date(0), new Date(0))).toBeTruthy()
expect(equalsFn(new Date(1), new Date(1))).toBeTruthy()
expect(equalsFn(new Date(0), new Date(1))).toBeFalsy()
expect(equalsFn(new Date(1), new Date(0))).toBeFalsy()
expect(equalsFn(new Date(0), {})).toBeFalsy()
expect(equalsFn({}, new Date(0))).toBeFalsy()
})test('ramda spec', () => {
expect(equalsFn({}, {})).toBeTruthy()expect(
equalsFn(
{
a: 1,
b: 2,
},
{
a: 1,
b: 2,
},
),
).toBeTruthy()expect(
equalsFn(
{
a: 2,
b: 3,
},
{
a: 2,
b: 3,
},
),
).toBeTruthy()expect(
equalsFn(
{
a: 2,
b: 3,
},
{
a: 3,
b: 3,
},
),
).toBeFalsy()expect(
equalsFn(
{
a: 2,
b: 3,
c: 1,
},
{
a: 2,
b: 3,
},
),
).toBeFalsy()
})test('works with boolean tuple', () => {
expect(equalsFn([true, false], [true, false])).toBeTruthy()
expect(equalsFn([true, false], [true, true])).toBeFalsy()
})test('works with equal objects within array', () => {
const objFirst = {
a: {
b: 1,
c: 2,
d: [1],
},
}
const objSecond = {
a: {
b: 1,
c: 2,
d: [1],
},
}const x = [1, 2, objFirst, null, '', []]
const y = [1, 2, objSecond, null, '', []]
expect(equalsFn(x, y)).toBeTruthy()
})test('works with different objects within array', () => {
const objFirst = { a: { b: 1 } }
const objSecond = { a: { b: 2 } }const x = [1, 2, objFirst, null, '', []]
const y = [1, 2, objSecond, null, '', []]
expect(equalsFn(x, y)).toBeFalsy()
})test('works with undefined as second argument', () => {
expect(equalsFn(1, undefined)).toBeFalsy()expect(equalsFn(undefined, undefined)).toBeTruthy()
})test('compare sets', () => {
const toCompareDifferent = new Set([{ a: 1 }, { a: 2 }])
const toCompareSame = new Set([{ a: 1 }, { a: 2 }, { a: 1 }])
const testSet = new Set([{ a: 1 }, { a: 2 }, { a: 1 }])
expect(equalsFn(toCompareSame, testSet)).toBeTruthy()
expect(equalsFn(toCompareDifferent, testSet)).toBeFalsy()
})test('compare simple sets', () => {
const testSet = new Set(['2', '3', '3', '2', '1'])
expect(equalsFn(new Set(['3', '2', '1']), testSet)).toBeTruthy()
expect(equalsFn(new Set(['3', '2', '0']), testSet)).toBeFalsy()
})test('various examples', () => {
expect(equalsFn([1, 2, 3], [1, 2, 3])).toBeTruthy()
expect(equalsFn([1, 2, 3], [1, 2])).toBeFalsy()
expect(equalsFn({}, {})).toBeTruthy()
})
```TypeScript test
```typescript
import { equals } from 'rambda'describe('R.equals', () => {
it('happy', () => {
const result = equals(4, 1)
result // $ExpectType boolean
})
it('with object', () => {
const foo = { a: 1 }
const bar = { a: 2 }
const result = equals(foo, bar)
result // $ExpectType boolean
})
it('curried', () => {
const result = equals(4)(1)result // $ExpectType boolean
})
})
```[](#equals)
### evolve
```typescript
evolve(rules: {
[K in keyof T]?: (x: T[K]) => T[K]
}): (obj: T) => T
```It takes object of functions as set of rules. These `rules` are applied to the `iterable` input to produce the result.
It doesn't support nested rules, i.e rules are only one level deep.```javascript
const input = {
foo: 2,
baz: 'baz',
}
const result = R.pipe(
input,
evolve({
foo: x => x + 1,
})
)
// => result is { foo: 3, baz: 'baz' }
```Try this R.evolve example in Rambda REPL
All TypeScript definitions
```typescript
evolve(rules: {
[K in keyof T]?: (x: T[K]) => T[K]
}): (obj: T) => T;
```R.evolve source
```javascript
import { mapObject } from './mapObject.js'
import { type } from './type.js'export function evolve(rules) {
return mapObject((x, prop) => type(rules[prop]) === 'Function' ? rules[prop](x): x)
}
```Tests
```javascript
import { evolve } from './evolve.js'test('happy', () => {
const rules = {
foo: x => x + 1,
}
const input = {
a: 1,
foo: 2,
nested: { bar: { z: 3 } },
}
const result = evolve(rules)(input)
expect(result).toEqual({
a: 1,
foo: 3,
nested: { bar: { z: 3 } },
})
})
```TypeScript test
```typescript
import { evolve, pipe } from 'rambda'it('R.evolve', () => {
const input = {
baz: 1,
foo: 2,
nested: {
a: 1,
bar: 3,
},
}
const result = pipe(input,
evolve({
foo: x => x + 1,
})
)
result.foo // $ExpectType number
result.baz // $ExpectType number
result.nested.a // $ExpectType number
})
```[](#evolve)
### excludes
Opposite of `R.includes`
`R.equals` is used to determine equality.
```javascript
const result = [
R.excludes('ar')('foo'),
R.excludes({a: 2})([{a: 1}])
]
// => [true, true ]
```Try this R.excludes example in Rambda REPL
[](#excludes)
### filter
```typescript
filter(
predicate: (value: T) => value is S,
): (list: T[]) => S[]
```It filters list or object `input` using a `predicate` function.
```javascript
const predicate = x => x > 1
const list = [1, 2, 3]
const result = R.filter(predicate)(list)
// => [2, 3]
```Try this R.filter example in Rambda REPL
All TypeScript definitions
```typescript
filter(
predicate: (value: T) => value is S,
): (list: T[]) => S[];
filter(
predicate: BooleanConstructor,
): (list: readonly T[]) => StrictNonNullable[];
filter(
predicate: BooleanConstructor,
): (list: T[]) => StrictNonNullable[];
filter(
predicate: (value: T) => boolean,
): (list: T[]) => T[];
```R.filter source
```javascript
export function filter(predicate) {
return list => {
if (!list) {
throw new Error('Incorrect iterable input')
}
let index = 0
const len = list.length
const willReturn = []while (index < len) {
if (predicate(list[index], index)) {
willReturn.push(list[index])
}index++
}return willReturn
}
}
```Tests
```javascript
import { filter } from './filter.js'test('happy', () => {
const isEven = n => n % 2 === 0expect(filter(isEven)([1, 2, 3, 4])).toEqual([2, 4])
})
```TypeScript test
```typescript
import { filter, mergeTypes, pipe } from 'rambda'const list = [1, 2, 3]
describe('R.filter with array', () => {
it('within pipe', () => {
const result = pipe(
list,
filter(x => {
x // $ExpectType number
return x > 1
}),
)
result // $ExpectType number[]
})
it('narrowing type', () => {
interface Foo {
a: number
}
interface Bar extends Foo {
b: string
}
type T = Foo | Bar
const testList: T[]= [{ a: 1 }, { a: 2 }, { a: 3 }]
const filterBar = (x: T): x is Bar => {
return typeof (x as Bar).b === 'string'
}
const result = pipe(
testList,
filter(filterBar),
)
result // $ExpectType Bar[]
})
it('narrowing type - readonly', () => {
interface Foo {
a: number
}
interface Bar extends Foo {
b: string
}
type T = Foo | Bar
const testList: T[]= [{ a: 1 }, { a: 2 }, { a: 3 }] as const
const filterBar = (x: T): x is Bar => {
return typeof (x as Bar).b === 'string'
}
const result = pipe(
testList,
filter(filterBar),
)
result // $ExpectType Bar[]
})
it('filtering NonNullable', () => {
const testList = [1, 2, null, undefined, 3]
const result = pipe(testList, filter(Boolean))
result // $ExpectType number[]
})
it('filtering NonNullable - readonly', () => {
const testList = [1, 2, null, undefined, 3] as const
const result = pipe(testList, filter(Boolean))
result.includes(1)
// @ts-expect-error
result.includes(4)
// @ts-expect-error
result.includes(undefined)
// @ts-expect-error
result.includes(null)
})
})
```[](#filter)
### filterObject
```typescript
filterObject(
valueMapper: (
value: EnumerableStringKeyedValueOf,
key: EnumerableStringKeyOf,
data: T,
) => boolean,
): (data: T) => U
```It loops over each property of `obj` and returns a new object with only those properties that satisfy the `predicate`.
```javascript
const result = R.filterObject(
(val, prop) => prop === 'a' || val > 1
)({a: 1, b: 2, c:3})
// => {a: 1, c: 3}
```Try this R.filterObject example in Rambda REPL
All TypeScript definitions
```typescript
filterObject(
valueMapper: (
value: EnumerableStringKeyedValueOf,
key: EnumerableStringKeyOf,
data: T,
) => boolean,
): (data: T) => U;
```R.filterObject source
```javascript
export function filterObject(predicate) {
return obj => {
const willReturn = {}for (const prop in obj) {
if (predicate(obj[prop], prop, obj)) {
willReturn[prop] = obj[prop]
}
}return willReturn
}
}
```Tests
```javascript
import { pipe } from './pipe.js'
import { filterObject } from './filterObject.js'test('happy', () => {
let testInput = { a: 1, b: 2, c: 3 }
const result = pipe(
testInput,
filterObject((x, prop, obj) => {
expect(prop).toBeOneOf(['a', 'b', 'c'])
expect(obj).toBe(testInput)
return x > 1
})
)
expect(result).toEqual({ b: 2, c: 3 })
})
```TypeScript test
```typescript
import { filterObject, pipe } from 'rambda'describe('R.filterObject', () => {
it('require explicit type', () => {
const result = pipe(
{ a: 1, b: 2 },
filterObject<{ b: number }>(a => {
a // $ExpectType number
return a > 1
}),
)
result.b // $ExpectType number
})
})
```[](#filterObject)
### find
```typescript
find(predicate: (x: T) => boolean): (list: T[]) => T | undefined
```It returns the first element of `list` that satisfy the `predicate`.
If there is no such element, it returns `undefined`.
```javascript
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 'bar'}, {foo: 1}]const result = R.find(predicate)(list)
// => {foo: 1}
```Try this R.find example in Rambda REPL
All TypeScript definitions
```typescript
find(predicate: (x: T) => boolean): (list: T[]) => T | undefined;
```R.find source
```javascript
export function find(predicate) {
return list => {
let index = 0
const len = list.lengthwhile (index < len) {
const x = list[index]
if (predicate(x)) {
return x
}index++
}
}
}
```Tests
```javascript
import { find } from './find.js'
import { propEq } from './propEq.js'const list = [{ a: 1 }, { a: 2 }, { a: 3 }]
test('happy', () => {
const fn = propEq(2, 'a')
expect(find(fn)(list)).toEqual({ a: 2 })
})test('nothing is found', () => {
const fn = propEq(4, 'a')
expect(find(fn)(list)).toBeUndefined()
})test('with empty list', () => {
expect(find(() => true)([])).toBeUndefined()
})
```TypeScript test
```typescript
import { find, pipe } from 'rambda'const list = [1, 2, 3]
describe('R.find', () => {
it('happy', () => {
const predicate = (x: number) => x > 2
const result = pipe(list, find(predicate))
result // $ExpectType number | undefined
})
})
```[](#find)
### findIndex
```typescript
findIndex(predicate: (x: T) => boolean): (list: T[]) => number
```It returns the index of the first element of `list` satisfying the `predicate` function.
If there is no such element, then `-1` is returned.
```javascript
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 'bar'}, {foo: 1}]const result = R.findIndex(predicate)(list)
// => 1
```Try this R.findIndex example in Rambda REPL
All TypeScript definitions
```typescript
findIndex(predicate: (x: T) => boolean): (list: T[]) => number;
```R.findIndex source
```javascript
export function findIndex(predicate) {
return list => {
const len = list.length
let index = -1while (++index < len) {
if (predicate(list[index])) {
return index
}
}return -1
}
}
```Tests
```javascript
import { findIndex } from './findIndex.js'
import { propEq } from './propEq.js'const list = [{ a: 1 }, { a: 2 }, { a: 3 }]
test('happy', () => {
expect(findIndex(propEq(2, 'a'))(list)).toBe(1)
expect(findIndex(propEq(1, 'a'))(list)).toBe(0)
expect(findIndex(propEq(4, 'a'))(list)).toBe(-1)
})
```TypeScript test
```typescript
import { findIndex, pipe } from 'rambda'const list = [1, 2, 3]
it('R.findIndex', () => {
const result = pipe(
list,
findIndex(x => x > 2),
)
result // $ExpectType number
})
```[](#findIndex)
### findLast
```typescript
findLast(fn: (x: T) => boolean): (list: T[]) => T | undefined
```It returns the last element of `list` satisfying the `predicate` function.
If there is no such element, then `undefined` is returned.
```javascript
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 0}, {foo: 1}]const result = R.findLast(predicate)(list)
// => {foo: 1}
```Try this R.findLast example in Rambda REPL
All TypeScript definitions
```typescript
findLast(fn: (x: T) => boolean): (list: T[]) => T | undefined;
```R.findLast source
```javascript
export function findLast(predicate) {
return list => {
let index = list.lengthwhile (--index >= 0) {
if (predicate(list[index])) {
return list[index]
}
}return undefined
}
}
```[](#findLast)
### findLastIndex
```typescript
findLastIndex(predicate: (x: T) => boolean): (list: T[]) => number
```It returns the index of the last element of `list` satisfying the `predicate` function.
If there is no such element, then `-1` is returned.
```javascript
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 0}, {foo: 1}]const result = R.findLastIndex(predicate)(list)
// => 1
```Try this R.findLastIndex example in Rambda REPL
All TypeScript definitions
```typescript
findLastIndex(predicate: (x: T) => boolean): (list: T[]) => number;
```R.findLastIndex source
```javascript
export function findLastIndex(fn) {
return list => {
let index = list.lengthwhile (--index >= 0) {
if (fn(list[index])) {
return index
}
}return -1
}
}
```Tests
```javascript
import { findLastIndex } from './findLastIndex.js'test('happy', () => {
const result = findLastIndex(x => x > 1)([1, 1, 1, 2, 3, 4, 1])
expect(result).toBe(5)
expect(findLastIndex(x => x === 0)([0, 1, 1, 2, 3, 4, 1])).toBe(0)
})
```TypeScript test
```typescript
import { findLastIndex, pipe } from 'rambda'const list = [1, 2, 3]
describe('R.findLastIndex', () => {
it('happy', () => {
const predicate = (x: number) => x > 2
const result = pipe(list, findLastIndex(predicate))
result // $ExpectType number
})
})
```[](#findLastIndex)
### findNth
```typescript
findNth(predicate: (x: T) => boolean, nth: number): (list: T[]) => T | undefined
```It returns the `nth` element of `list` that satisfy the `predicate` function.
```javascript
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 0}, {foo: 1}, {foo: 2}, {foo: 3}]const result = R.findNth(predicate, 2)(list)
// => {foo: 2}
```Try this R.findNth example in Rambda REPL
All TypeScript definitions
```typescript
findNth(predicate: (x: T) => boolean, nth: number): (list: T[]) => T | undefined;
```R.findNth source
```javascript
export function findNth(predicate, nth) {
return list => {
let index = 0
const len = list.lengthwhile (index < len) {
const x = list[index]
if (predicate(x)) {
if (nth === 0) return x
nth--
}index++
}
}
}
```Tests
```javascript
import { findNth } from './findNth.js'const list = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }]
test('happy', () => {
const fn = x => x.a > 1
expect(findNth(fn,1)(list)).toEqual({ a: 3 })
})test('nothing is found', () => {
const fn = x => x.a > 4
expect(findNth(fn,1)(list)).toBeUndefined()
})
```[](#findNth)
### flatMap
```typescript
flatMap(transformFn: (x: T extends any[] ? T[number]: never) => U): (listOfLists: T[]) => U[]
```It maps `fn` over `list` and then flatten the result by one-level.
```javascript
const duplicate = n => [ n, n ]
const list = [ 1, 2, 3 ]const result = R.flatMap(duplicate)(list)
// => [ 1, 1, 2, 2, 3, 3 ]
```Try this R.flatMap example in Rambda REPL
All TypeScript definitions
```typescript
flatMap(transformFn: (x: T extends any[] ? T[number]: never) => U): (listOfLists: T[]) => U[];
```R.flatMap source
```javascript
export function flatMap(fn) {
return list => [].concat(...list.map(fn))
}
```Tests
```javascript
import { flatMap } from './flatMap.js'const duplicate = n => [n, n]
test('happy', () => {
const fn = x => [x * 2]
const list = [1, 2, 3]const result = flatMap(fn)(list)
expect(result).toEqual([2, 4, 6])
})test('maps then flattens one level', () => {
expect(flatMap(duplicate)([1, 2, 3])).toEqual([1, 1, 2, 2, 3, 3])
})test('maps then flattens one level', () => {
expect(flatMap(duplicate)([1, 2, 3])).toEqual([1, 1, 2, 2, 3, 3])
})test('flattens only one level', () => {
const nest = n => [[n]]
expect(flatMap(nest)([1, 2, 3])).toEqual([[1], [2], [3]])
})test('can compose', () => {
function dec(x) {
return [x - 1]
}
function times2(x) {
return [x * 2]
}const mdouble = flatMap(times2)
const mdec = flatMap(dec)
expect(mdec(mdouble([10, 20, 30]))).toEqual([19, 39, 59])
})
```TypeScript test
```typescript
import { flatMap, pipe } from 'rambda'describe('R.flatMap', () => {
it('happy', () => {
const listOfLists: string[][] = [
['f', 'bar'],
['baz', 'b'],
]
const result = pipe(
listOfLists,
x => x,
flatMap(x => {
x // $ExpectType string
return Number(x) + 1
}),
)
result // $ExpectType number[]
})
})
```[](#flatMap)
### flatten
```typescript
flatten(list: any[]): T[]
```It deeply flattens an array.
You must pass expected output type as a type argument.```javascript
const result = R.flatten([
1,
2,
[3, 30, [300]],
[4]
])
// => [ 1, 2, 3, 30, 300, 4 ]
```Try this R.flatten example in Rambda REPL
All TypeScript definitions
```typescript
flatten(list: any[]): T[];
```R.flatten source
```javascript
import { isArray } from './_internals/isArray.js'export function flatten(list, input) {
const willReturn = input === undefined ? [] : inputfor (let i = 0; i < list.length; i++) {
if (isArray(list[i])) {
flatten(list[i], willReturn)
} else {
willReturn.push(list[i])
}
}return willReturn
}
```Tests
```javascript
import { flatten } from './flatten.js'test('happy', () => {
expect(flatten([1, 2, 3, [[[[[4]]]]]])).toEqual([1, 2, 3, 4])expect(flatten([1, [2, [[3]]], [4]])).toEqual([1, 2, 3, 4])
expect(flatten([1, [2, [[[3]]]], [4]])).toEqual([1, 2, 3, 4])
expect(flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]])).toEqual([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
])
})test('readme example', () => {
const result = flatten([1, 2, [3, 30, [300]], [4]])
expect(result).toEqual([1, 2, 3, 30, 300, 4])
})
```TypeScript test
```typescript
import { flatten, pipe } from 'rambda'describe('flatten', () => {
it('happy', () => {
const result = pipe([1, 2, [3, [4]]], flatten)
result // $ExpectType number[]
})
})
```[](#flatten)
### groupBy
It splits `list` according to a provided `groupFn` function and returns an object.
```javascript
const list = [ 'a', 'b', 'aa', 'bb' ]
const groupFn = x => x.lengthconst result = R.groupBy(groupFn, list)
// => { '1': ['a', 'b'], '2': ['aa', 'bb'] }
```Try this R.groupBy example in Rambda REPL
[](#groupBy)
### head
```typescript
head(listOrString: T): T extends string ? string :
T extends [] ? undefined:
T extends readonly [infer F, ...infer R] ? F :
T extends readonly [infer F] ? F :
T extends [infer F] ? F :
T extends [infer F, ...infer R] ? F :
T extends unknown[] ? T[number] :
undefined
```It returns the first element of list or string `input`. It returns `undefined` if array has length of 0.
```javascript
const result = [
R.head([1, 2, 3]),
R.head('foo')
]
// => [1, 'f']
```Try this R.head example in Rambda REPL
All TypeScript definitions
```typescript
head(listOrString: T): T extends string ? string :
T extends [] ? undefined:
T extends readonly [infer F, ...infer R] ? F :
T extends readonly [infer F] ? F :
T extends [infer F] ? F :
T extends [infer F, ...infer R] ? F :
T extends unknown[] ? T[number] :
undefined;
```R.head source
```javascript
export function head(listOrString) {
if (typeof listOrString === 'string') {
return listOrString[0] || ''
}return listOrString[0]
}
```Tests
```javascript
import { head } from './head.js'test('head', () => {
expect(head(['fi', 'fo', 'fum'])).toBe('fi')
expect(head([])).toBeUndefined()
expect(head('foo')).toBe('f')
expect(head('')).toBe('')
})
```TypeScript test
```typescript
import { head, last } from 'rambda'export const mixedList = [1, 'foo', 3, 'bar']
export const mixedListConst = [1, 'foo', 3, 'bar'] as const
export const numberList = [1, 2, 3]
export const numberListConst = [1, 2, 3] as const
export const emptyList = []
export const emptyString = ''
export const string = 'foo'describe('R.head', () => {
it('string', () => {
head(string) // $ExpectType string
last(string) // $ExpectType string
})
it('empty string', () => {
head(emptyString) // $ExpectType string
last(emptyString) // $ExpectType string
})
it('array', () => {
head(numberList) // $ExpectType number
head(numberListConst) // $ExpectType 1last(numberList) // $ExpectType number
last(numberListConst) // $ExpectType 3
})
it('empty array', () => {
const list = [] as const
head(emptyList) // $ExpectType never
head(list) // $ExpectType undefined
last(emptyList) // $ExpectType never
last(list) // $ExpectType undefined
})it('mixed', () => {
head(mixedList) // $ExpectType string | number
head(mixedListConst) // $ExpectType 1
last(mixedList) // $ExpectType string | number
last(mixedListConst) // $ExpectType "bar"
})
})
```[](#head)
### includes
```typescript
includes(valueToFind: T): (input: string) => boolean
```If `input` is string, then this method work as native `String.includes`.
If `input` is array, then `R.equals` is used to define if `valueToFind` belongs to the list.
```javascript
const result = [
R.includes('oo')('foo'),
R.includes({a: 1})([{a: 1}])
]
// => [true, true ]
```Try this R.includes example in Rambda REPL
All TypeScript definitions
```typescript
includes(valueToFind: T): (input: string) => boolean;
includes(valueToFind: T): (input: T[]) => boolean;
```R.includes source
```javascript
import { isArray } from './_internals/isArray.js'
import { _indexOf } from './equals.js'export function includes(valueToFind) {
return iterable => {
if (typeof iterable === 'string') {
return iterable.includes(valueToFind)
}
if (!iterable) {
throw new TypeError(`Cannot read property \'indexOf\' of ${iterable}`)
}
if (!isArray(iterable)) {
return false
}return _indexOf(valueToFind, iterable) > -1
}
}
```Tests
```javascript
import { includes } from './includes.js'test('with string as iterable', () => {
const str = 'foo bar'expect(includes('bar')(str)).toBeTruthy()
expect(includes('never')(str)).toBeFalsy()
})test('with array as iterable', () => {
const arr = [1, 2, 3]expect(includes(2)(arr)).toBeTruthy()
expect(includes(4)(arr)).toBeFalsy()
})test('with list of objects as iterable', () => {
const arr = [{ a: 1 }, { b: 2 }, { c: 3 }]expect(includes({ c: 3 })(arr)).toBeTruthy()
})test('with NaN', () => {
const result = includes(Number.NaN)([Number.NaN])
expect(result).toBeTruthy()
})test('with wrong input that does not throw', () => {
const result = includes(1)(/foo/g)
expect(result).toBeFalsy()
})
```TypeScript test
```typescript
import { includes, pipe } from 'rambda'describe('R.includes', () => {
it('happy', () => {
const list = [{ a: { b: '1' } }, { a: { b: '2' } }, { a: { b: '3' } }]
const result = pipe(list, includes({ a: { b: '1' } }))
result // $ExpectType boolean
})
it('with string', () => {
const result = pipe('foo', includes('bar'))
result // $ExpectType boolean
})
})
```[](#includes)
### indexOf
It uses `R.equals` for list of objects/arrays or native `indexOf` for any other case.
```javascript
const result = [
R.indexOf({a:1})([{a:1}, {a:2}]),
R.indexOf(2)([1, 2, 3]),
]
// => [0, 1]
```Try this R.indexOf example in Rambda REPL
[](#indexOf)
### init
```typescript
init(input: T): T extends readonly [...infer U, any] ? U : [...T]
```It returns all but the last element of list or string `input`.
```javascript
const result = [
R.init([1, 2, 3]) ,
R.init('foo') // => 'fo'
]
// => [[1, 2], 'fo']
```Try this R.init example in Rambda REPL
All TypeScript definitions
```typescript
init(input: T): T extends readonly [...infer U, any] ? U : [...T];
init(input: string): string;
```R.init source
```javascript
import { baseSlice } from './_internals/baseSlice.js'export function init(input) {
if (typeof input === 'string') {
return input.slice(0, -1)
}return input.length ? baseSlice(input, 0, -1) : []
}
```Tests
```javascript
import { init } from './init.js'test('with array', () => {
expect(init([1, 2, 3])).toEqual([1, 2])
expect(init([1, 2])).toEqual([1])
expect(init([1])).toEqual([])
expect(init([])).toEqual([])
expect(init([])).toEqual([])
expect(init([1])).toEqual([])
})test('with string', () => {
expect(init('foo')).toBe('fo')
expect(init('f')).toBe('')
expect(init('')).toBe('')
})
```TypeScript test
```typescript
import { init } from 'rambda'describe('R.init', () => {
it('with string', () => {
const result = init('foo')result // $ExpectType string
})
it('with list - one type', () => {
const result = init([1, 2, 3])result // $ExpectType number[]
})
it('with list - mixed types', () => {
const result = init([1, 2, 3, 'foo', 'bar'])result // $ExpectType (string | number)[]
})
})
```[](#init)
### innerJoin
It returns a new list by applying a `predicate` function to all elements of `list1` and `list2` and keeping only these elements where `predicate` returns `true`.
```javascript
const list1 = [1, 2, 3, 4, 5]
const list2 = [4, 5, 6]
const predicate = (x, y) => x >= y
const result = R.innerJoin(predicate, list1)(list2)
// => [4, 5]
```Try this R.innerJoin example in Rambda REPL
[](#innerJoin)
### interpolate
```typescript
interpolate(inputWithTags: string): (templateArguments: object) => string
```It generates a new string from `inputWithTags` by replacing all `{{x}}` occurrences with values provided by `templateArguments`.
```javascript
const inputWithTags = 'foo is {{bar}} even {{a}} more'
const templateArguments = {"bar":"BAR", a: 1}const result = R.interpolate(inputWithTags, templateArguments)
const expected = 'foo is BAR even 1 more'
// => `result` is equal to `expected`
```Try this R.interpolate example in Rambda REPL
All TypeScript definitions
```typescript
interpolate(inputWithTags: string): (templateArguments: object) => string;// API_MARKER_END
// ============================================export as namespace R
```R.interpolate source
```javascript
const getOccurrences = input => input.match(/{{\s*.+?\s*}}/g)
const getOccurrenceProp = occurrence => occurrence.replace(/{{\s*|\s*}}/g, '')const replace = ({ inputHolder, prop, replacer }) => {
const regexBase = `{{${prop}}}`
const regex = new RegExp(regexBase, 'g')
return inputHolder.replace(regex, replacer)
}export function interpolate(input) {
return templateInput => {
const occurrences = getOccurrences(input)
if (occurrences === null) {
return input
}
let inputHolder = inputfor (const occurrence of occurrences) {
const prop = getOccurrenceProp(occurrence)
inputHolder = replace({
inputHolder,
prop,
replacer: templateInput[prop],
})
}return inputHolder
}
}
```Tests
```javascript
import { interpolate } from './interpolate.js'
import { pipe } from './pipe.js'test('happy', () => {
const result = pipe(
{ name: 'John', age: 30 },
interpolate('My name is {{name}} and I am {{age}} years old')
)
expect(result).toBe('My name is John and I am 30 years old')
})
```TypeScript test
```typescript
import { interpolate } from 'rambda'const templateInput = 'foo {{x}} baz'
const templateArguments = { x: 'led zeppelin' }it('R.interpolate', () => {
const result = interpolate(templateInput)(templateArguments)result // $ExpectType string
})
```[](#interpolate)
### intersection
It loops through `listA` and `listB` and returns the intersection of the two according to `R.equals`.
> :boom: There is slight difference between Rambda and Ramda implementation. Ramda.intersection(['a', 'b', 'c'], ['c', 'b']) result is "[ 'c', 'b' ]", but Rambda result is "[ 'b', 'c' ]".
```javascript
const listA = [ { id : 1 }, { id : 2 }, { id : 3 }, { id : 4 } ]
const listB = [ { id : 3 }, { id : 4 }, { id : 5 }, { id : 6 } ]const result = R.intersection(listA)(listB)
// => [{ id : 3 }, { id : 4 }]
```Try this R.intersection example in Rambda REPL
[](#intersection)
### intersperse
It adds a `separator` between members of `list`.
```javascript
const list = [ 0, 1, 2, 3 ]
const separator = 10
const result = R.intersperse(separator)(list)
// => [0, 10, 1, 10, 2, 10, 3]
```Try this R.intersperse example in Rambda REPL
[](#intersperse)
### join
```typescript
join(glue: string): (list: T[]) => string
```It returns a string of all `list` instances joined with a `glue`.
```javascript
R.join('-', [1, 2, 3]) // => '1-2-3'
```Try this R.join example in Rambda REPL
All TypeScript definitions
```typescript
join(glue: string): (list: T[]) => string;
```R.join source
```javascript
export function join(glue) {
return list => list.join(glue)
}
```TypeScript test
```typescript
import { join, pipe } from 'rambda'it('R.join', () => {
const result = pipe([1, 2, 3], join('|'))
result // $ExpectType string
})
```[](#join)
### last
```typescript
last(listOrString: T): T extends string ? string :
T extends [] ? undefined :
T extends readonly [...infer R, infer L] ? L :
T extends readonly [infer L] ? L :
T extends [infer L] ? L :
T extends [...infer R, infer L] ? L :
T extends unknown[] ? T[number] :
undefined
```It returns the last element of `input`, as the `input` can be either a string or an array. It returns `undefined` if array has length of 0.
```javascript
const result = [
R.last([1, 2, 3]),
R.last('foo'),
]
// => [3, 'o']
```Try this R.last example in Rambda REPL
All TypeScript definitions
```typescript
last(listOrString: T): T extends string ? string :
T extends [] ? undefined :
T extends readonly [...infer R, infer L] ? L :
T extends readonly [infer L] ? L :
T extends [infer L] ? L :
T extends [...infer R, infer L] ? L :
T extends unknown[] ? T[number] :
undefined;
```R.last source
```javascript
export function last(listOrString) {
if (typeof listOrString === 'string') {
return listOrString[listOrString.length - 1] || ''
}return listOrString[listOrString.length - 1]
}
```Tests
```javascript
import { last } from './last.js'test('with list', () => {
expect(last([1, 2, 3])).toBe(3)
expect(last([])).toBeUndefined()
})test('with string', () => {
expect(last('abc')).toBe('c')
expect(last('')).toBe('')
})
```[](#last)
### lastIndexOf
```typescript
lastIndexOf(target: T): (list: T[]) => number
```It returns the last index of `target` in `list` array.
`R.equals` is used to determine equality between `target` and members of `list`.
If there is no such index, then `-1` is returned.
```javascript
const list = [1, 2, 3, 1, 2, 3]
const result = [
R.lastIndexOf(2)(list),
R.lastIndexOf(4)(list),
]
// => [4, -1]
```Try this R.lastIndexOf example in Rambda REPL
All TypeScript definitions
```typescript
lastIndexOf(target: T): (list: T[]) => number;
```R.lastIndexOf source
```javascript
import { _lastIndexOf } from './equals.js'export function lastIndexOf(valueToFind) {
return list => _lastIndexOf(valueToFind, list)
}
```Tests
```javascript
import { lastIndexOf } from './lastIndexOf.js'test('with NaN', () => {
expect(lastIndexOf(Number.NaN)([Number.NaN])).toBe(0)
})test('will throw with bad input', () => {
expect(() => indexOf([])(true)).toThrowError('indexOf is not defined')
})test('without list of objects - no R.equals', () => {
expect(lastIndexOf(3)([1, 2, 3, 4])).toBe(2)
expect(lastIndexOf(10)([1, 2, 3, 4])).toBe(-1)
})test('list of objects uses R.equals', () => {
const listOfObjects = [{ a: 1 }, { b: 2 }, { c: 3 }]
expect(lastIndexOf({ c: 4 })(listOfObjects)).toBe(-1)
expect(lastIndexOf({ c: 3 })(listOfObjects)).toBe(2)
})test('list of arrays uses R.equals', () => {
const listOfLists = [[1], [2, 3], [2, 3, 4], [2, 3], [1], []]
expect(lastIndexOf([])(listOfLists)).toBe(5)
expect(lastIndexOf([1])(listOfLists)).toBe(4)
expect(lastIndexOf([2, 3, 4])(listOfLists)).toBe(2)
expect(lastIndexOf([2, 3, 5])(listOfLists)).toBe(-1)
})
```TypeScript test
```typescript
import { lastIndexOf, pipe } from 'rambda'describe('R.lastIndexOf', () => {
const result = pipe([{ a: 1 }, { a: 2 }, { a: 3 }], lastIndexOf({ a: 2 }))
result // $ExpectType number
})
```[](#lastIndexOf)
### map
```typescript
map(
fn: (value: T[number], index: number) => U,
): (data: T) => Mapped
```It returns the result of looping through `iterable` with `fn`.
It works with both array and object.
```javascript
const fn = x => x * 2const iterable = [1, 2]
const obj = {a: 1, b: 2}const result = R.map(fn)(iterable),
// => [2, 4]
```Try this R.map example in Rambda REPL
All TypeScript definitions
```typescript
map(
fn: (value: T[number], index: number) => U,
): (data: T) => Mapped;
map(
fn: (value: T[number]) => U,
): (data: T) => Mapped;
map(
fn: (value: T[number], index: number) => U,
data: T
) : Mapped;
map(
fn: (value: T[number]) => U,
data: T
) : Mapped;
```R.map source
```javascript
export function map(fn) {
return list => {
let index = 0
const willReturn = Array(list.length)
while (index < list.length) {
willReturn[index] = fn(list[index], index)
index++
}
return willReturn
}
}
```Tests
```javascript
import { map } from './map.js'const double = x => x * 2
it('happy', () => {
expect(map(double)([1, 2, 3])).toEqual([2, 4, 6])
})
```TypeScript test
```typescript
import { map, pipe } from 'rambda'const list = [1, 2, 3]
it('R.map', () => {
const result = pipe(
list,
x => x,
map(x => {
x // $ExpectType number
return String(x)
}),
)
result // $ExpectType string[]
})
```[](#map)
### mapAsync
```typescript
mapAsync(
fn: (value: T[number], index: number) => Promise,
): (data: T) => Promise>
```Sequential asynchronous mapping with `fn` over members of `list`.
```javascript
async function fn(x){
await R.delay(1000)return x+1
}const result = await R.mapAsync(fn)([1, 2, 3])
// `result` resolves after 3 seconds to `[2, 3, 4]`
```Try this R.mapAsync example in Rambda REPL
All TypeScript definitions
```typescript
mapAsync(
fn: (value: T[number], index: number) => Promise,
): (data: T) => Promise>;
mapAsync(
fn: (value: T[number]) => Promise,
): (data: T) => Promise>;
mapAsync(
fn: (value: T[number], index: number) => Promise,
data: T
): Promise>;
mapAsync(
fn: (value: T[number]) => Promise,
data: T
): Promise>;
```R.mapAsync source
```javascript
export function mapAsync(fn) {
return async list => {
const willReturn = []
let i = 0
for (const a of list) {
willReturn.push(await fn(a, i++))
}return willReturn
}
}
```Tests
```javascript
import { delay } from './delay.js'
import { map } from './map.js'
import { mapAsync } from './mapAsync.js'
import { pipeAsync } from './pipeAsync.js'const rejectDelay = a =>
new Promise((_, reject) => {
setTimeout(() => {
reject(a + 20)
}, 100)
})test('happy', async () => {
const indexes = []
const fn = async (x, prop) => {
await delay(100)
indexes.push(prop)
return x + 1
}
const result = await mapAsync(fn)([1, 2, 3])
expect(result).toEqual([2, 3, 4])
expect(indexes).toEqual([0, 1, 2])
})test('with R.pipeAsync', async () => {
const fn = async x => x + 1
const result = await pipeAsync(
[1, 2, 3],
map(x => x + 1),
mapAsync(async x => {
delay(x)return x
}),
mapAsync(fn),
map(x => x * 10),
)
expect(result).toEqual([30, 40, 50])
})test('error', async () => {
try {
await mapAsync(rejectDelay)([1, 2, 3])
} catch (err) {
expect(err).toBe(21)
}
})
```TypeScript test
```typescript
import { mapAsync, pipeAsync } from 'rambda'
import { delay } from 'rambdax'const list = ['a', 'bc', 'def']
it('R.mapAsync', async () => {
const fn = async (x:unknown) => x as number + 1const result = await pipeAsync(
list,
mapAsync(async x => {
await delay(100)
x // $ExpectType string
return x.length % 2 ? x.length + 1 : x.length + 10
}),
x => x,
mapAsync(fn),
mapAsync(async x => {
await delay(100)
return x + 1
}),
)
result // $ExpectType number[]
})
```[](#mapAsync)
### mapKeys
```typescript
mapKeys(fn: (prop: string, value: T) => string): (obj: Record) => Record
```It returns a copy of `obj` with keys transformed by `fn`.
```javascript
const result = R.mapKeys(
(key, value) => key.toUpperCase()+value
)(
{ a: 1, b: 2 }
)
// => { A1: 1, B2: 2 }
```Try this R.mapKeys example in Rambda REPL
All TypeScript definitions
```typescript
mapKeys(fn: (prop: string, value: T) => string): (obj: Record) => Record;
```R.mapKeys source
```javascript
export function mapKeys(fn) {
return obj => {
const willReturn = {}Object.keys(obj).forEach(key => {
willReturn[fn(key, obj[key])] = obj[key]
})return willReturn
}
}
```Tests
```javascript
import { mapKeys } from "./mapKeys.js"test('happy', () => {
const result = mapKeys((prop, x) => `${ prop }-${x}`)({a:1, b: 2 })
const expected = { 'a-1': 1, 'b-2': 2 }expect(result).toEqual(expected)
})
```TypeScript test
```typescript
import { mapKeys, pipe } from 'rambda'it('R.mapKeys', () => {
const result = pipe(
{ a: 1, b: 2 },
mapKeys((prop, x) => `${prop}-${x}`),
mapKeys(prop => `${prop}-${prop}`),
)
result // $ExpectType Record
})
```[](#mapKeys)
### mapObject
```typescript
mapObject(
valueMapper: (
value: EnumerableStringKeyedValueOf,
key: EnumerableStringKeyOf,
data: T,
) => Value,
): (data: T) => MappedValues
``````javascript
const fn = (val, prop) => `${prop}-${val}`
const obj = {a: 1, b: 2}const result = R.mapObject(fn)(obj)
// => {a: 'a-1', b: 'b-2'}
```Try this R.mapObject example in Rambda REPL
All TypeScript definitions
```typescript
mapObject(
valueMapper: (
value: EnumerableStringKeyedValueOf,
key: EnumerableStringKeyOf,
data: T,
) => Value,
): (data: T) => MappedValues;
```R.mapObject source
```javascript
import { keys } from './_internals/keys.js'export function mapObject(fn) {
return obj => {
let index = 0
const objKeys = keys(obj)
const len = objKeys.length
const willReturn = {}while (index < len) {
const key = objKeys[index]
willReturn[key] = fn(obj[key], key, obj)
index++
}return willReturn
}
}
```Tests
```javascript
import { mapObject } from './mapObject.js'const double = x => x * 2
it('happy', () => {
expect(mapObject(double)({ a: 1, b: 2, c: 3 })).toEqual({ a: 2, b: 4, c: 6 })
})
```TypeScript test
```typescript
import { mapObject, pipe } from 'rambda'describe('R.mapObject', () => {
it('iterable with one arguments', () => {
const result = pipe(
{ a: 1 },
mapObject(a => {
a // $ExpectType number
return `${a}`
}),
)result // $ExpectType { a: string; }
})
it('iterable with two three arguments', () => {
const result = pipe(
{ a: 1, b: 'foo' },
mapObject((a, b) => {
a // $ExpectType string | number
b // $ExpectType "a" | "b"
return `${a}`
}),
)result // $ExpectType { a: string; b: string; }
})
it('iterable with three arguments', () => {
const result = pipe(
{ a: 1, b: 'foo' },
mapObject((a, b, c) => {
a // $ExpectType string | number
b // $ExpectType "a" | "b"
c // $ExpectType { a: number; b: string; }
return `${a}`
}),
)result // $ExpectType { a: string; b: string; }
})
})
```[](#mapObject)
### mapObjectAsync
```typescript
mapObjectAsync(
valueMapper: (
value: EnumerableStringKeyedValueOf,
key: EnumerableStringKeyOf,
data: T,
) => Promise,
): (data: T) => Promise>
```All TypeScript definitions
```typescript
mapObjectAsync(
valueMapper: (
value: EnumerableStringKeyedValueOf,
key: EnumerableStringKeyOf,
data: T,
) => Promise,
): (data: T) => Promise>;
```R.mapObjectAsync source
```javascript
export function mapObjectAsync(fn) {
return async obj => {
const willReturn = {}
for (const prop in obj) {
willReturn[prop] = await fn(obj[prop], prop)
}return willReturn
}
}
```Tests
```javascript
import { delay } from './delay.js'
import { mapObjectAsync } from './mapObjectAsync.js'
import { pipeAsync } from './pipeAsync.js'test('happy', async () => {
const indexes = []
const result = await pipeAsync(
{ a: 1, b: 2 },
mapObjectAsync(async (x, i) => {
await delay(100)
indexes.push(i)
return x + 1
}),
)
expect(indexes).toEqual(['a', 'b'])
expect(result).toEqual({
a: 2,
b: 3,
})
})
```TypeScript test
```typescript
import { mapObjectAsync, pipeAsync } from 'rambda'
import { delay } from 'rambdax'it('R.mapObjectAsync', async () => {
const result = await pipeAsync(
{ a: 'foo', b: 'bar' },
mapObjectAsync(async x => {
await delay(100)
x // $ExpectType string
return x.length % 2 ? x.length + 1 : x.length + 10
}),
x => x,
mapObjectAsync(async x => {
await delay(100)
return x + 1
}),
)
result.a // $ExpectType number
result.b // $ExpectType number
})
```[](#mapObjectAsync)
### mapParallelAsync
```typescript
mapParallelAsync(
fn: (value: T[number], index: number) => Promise,
): (data: T) => Promise>
```Wrapper around `Promise.all` for asynchronous mapping with `fn` over members of `list`.
All TypeScript definitions
```typescript
mapParallelAsync(
fn: (value: T[number], index: number) => Promise,
): (data: T) => Promise>;
mapParallelAsync(
fn: (value: T[number]) => Promise,
): (data: T) => Promise>;
mapParallelAsync(
fn: (value: T[number], index: number) => Promise,
data: T
): Promise>;
mapParallelAsync(
fn: (value: T[number]) => Promise,
data: T
): Promise>;
```R.mapParallelAsync source
```javascript
export function mapParallelAsync(fn) {
return async list => Promise.all(list.map((x, i) => fn(x, i)))
}
```Tests
```javascript
import { pipeAsync } from './pipeAsync.js'
import { delay } from './delay.js'
import { mapParallelAsync } from './mapParallelAsync.js'test('happy', async () => {
const fn = async (x, i) => {
await delay(100)return x + i
}
const result = await mapParallelAsync(fn)([ 1, 2, 3 ])
expect(result).toEqual([ 1, 3, 5 ])
})test('pipeAsync', async () => {
const result = await pipeAsync(
[1, 2, 3],
mapParallelAsync(async x => {
await delay(100)return x + 1
})
)
expect(result).toEqual([ 2,3,4 ])
})
```[](#mapParallelAsync)
### match
```typescript
match(regExpression: RegExp): (str: string) => string[]
```Curried version of `String.prototype.match` which returns empty array, when there is no match.
```javascript
const result = [
R.match('a', 'foo'),
R.match(/([a-z]a)/g, 'bananas')
]
// => [[], ['ba', 'na', 'na']]
```Try this R.match example in Rambda REPL
All TypeScript definitions
```typescript
match(regExpression: RegExp): (str: string) => string[];
```R.match source
```javascript
export function match(pattern) {
return input => {
const willReturn = input.match(pattern)return willReturn === null ? [] : willReturn
}
}
```Tests
```javascript
import { match } from './match.js'test('happy', () => {
expect(match(/a./g)('foo bar baz')).toEqual(['ar', 'az'])
})test('fallback', () => {
expect(match(/a./g)('foo')).toEqual([])
})test('with string', () => {
expect(match('a')('foo')).toEqual([])
})
```TypeScript test
```typescript
import { match } from 'rambda'const str = 'foo bar'
describe('R.match', () => {
it('happy', () => {
const result = match(/foo/)(str)
result // $ExpectType string[]
})
})
```[](#match)
### maxBy
It returns the greater value between `x` and `y` according to `compareFn` function.
```javascript
const compareFn = Math.absR.maxBy(compareFn, 5, -7) // => -7
```Try this R.maxBy example in Rambda REPL
[](#maxBy)
### merge
It creates a copy of `target` object with overwritten `newProps` properties.
[](#merge)
### mergeTypes
```typescript
mergeTypes(x: T): MergeTypes
```Helper to merge all calculated TypeScript definitions into one definition.
It returns its input and it is intended to be used as last method inside `R.pipe` chain.All TypeScript definitions
```typescript
mergeTypes(x: T): MergeTypes;
```R.mergeTypes source
```javascript
export function mergeTypes(x) {
return x
}
```[](#mergeTypes)
### minBy
It returns the lesser value between `x` and `y` according to `compareFn` function.
```javascript
const compareFn = Math.absR.minBy(compareFn, -5, 2) // => -5
```Try this R.minBy example in Rambda REPL
[](#minBy)
### modifyProp
```typescript
modifyProp(
prop: K,
fn: (x: T[K]) => T[K],
): (target: T) => T
```It changes a property with the result of transformer function.
```javascript
const person = {
name : 'foo',
age : 20,
}
const result = R.modifyProp('age', x => x + 1)(person)
// => {name: 'foo', age: 21}
```Try this R.modifyProp example in Rambda REPL
All TypeScript definitions
```typescript
modifyProp(
prop: K,
fn: (x: T[K]) => T[K],
): (target: T) => T;
```R.modifyProp source
```javascript
import { isArray } from './_internals/isArray.js'
import { update } from './update.js'function modifyFn(property, fn, list) {
if (list[property] === undefined) {
return list
}
if (isArray(list)) {
return update(property, fn(list[property]))(list)
}return {
...list,
[property]: fn(list[property]),
}
}export function modifyProp(property, fn) {
return obj => modifyFn(property, fn, obj)
}
```Tests
```javascript
import { modifyProp } from './modifyProp.js'const person = {
name: 'foo',
age: 20,
}test('happy', () => {
expect(modifyProp('age', x => x + 1)(person)).toEqual({
name: 'foo',
age: 21,
})
})test('property is missing', () => {
expect(modifyProp('foo', x => x + 1)(person)).toEqual(person)
})test('adjust if `array` at the given key with the `transformation` function', () => {
expect(modifyProp(1, x => x + 1)([100, 1400])).toEqual([100, 1401])
})
```TypeScript test
```typescript
import { modifyProp, pipe } from 'rambda'it('R.modify', () => {
const result = pipe(
{ a: 1, b: 2, c: { d: 3 } },
modifyProp('a', val => val + 1),
)
result // $ExpectType { a: number; b: number; c: { d: number; }; }pipe(
{ a: 1, b: 2, c: { d: 3 } },
// @ts-expect-error
modifyProp('ax', val => val + 1),
)pipe(
{ a: 1, b: 2, c: { d: 3 } },
// @ts-expect-error
modifyProp('a', val => String(val)),
)
})
```[](#modifyProp)
### none
```typescript
none(predicate: (x: T) => boolean): (list: T[]) => boolean
```It returns `true`, if all members of array `list` returns `false`, when applied as argument to `predicate` function.
```javascript
const list = [ 0, 1, 2, 3, 4 ]
const predicate = x => x > 6const result = R.none(predicate)(arr)
// => true
```Try this R.none example in Rambda REPL
All TypeScript definitions
```typescript
none(predicate: (x: T) => boolean): (list: T[]) => boolean;
```R.none source
```javascript
export function none(predicate) {
return list => {
for (let i = 0; i < list.length; i++) {
if (predicate(list[i])) {
return false
}
}return true
}
}
```Tests
```javascript
import { none } from './none.js'const isEven = n => n % 2 === 0
test('when true', () => {
expect(none(isEven)([1, 3, 5, 7])).toBeTruthy()
})test('when false', () => {
expect(none(input => input > 1)([1, 2, 3])).toBeFalsy()
})
```TypeScript test
```typescript
import { none, pipe } from 'rambda'describe('R.none', () => {
it('happy', () => {
const result = pipe(
[1, 2, 3],
none(x => x > 0),
)
result // $ExpectType boolean
})
})
```[](#none)
### objectIncludes
```typescript
objectIncludes(specification: T): (obj: Partial) => boolean
```It will return `true` if `specification` object fully or partially include `obj` object.
`R.equals` is used to determine equality.
```javascript
const specification = { a : { b : 1 } }
const input = {
a : { b : 1 },
c : 2
}const result = objectIncludes(specification)(input)
// => true
```Try this R.objectIncludes example in Rambda REPL
All TypeScript definitions
```typescript
objectIncludes(specification: T): (obj: Partial) => boolean;
```R.objectIncludes source
```javascript
import { equals } from './equals.js'
import { filterObject } from './filterObject.js'export function objectIncludes(condition) {
return obj => {
const result = filterObject((conditionValue, conditionProp) =>
equals(conditionValue)(obj[conditionProp]),
)(condition)return Object.keys(result).length === Object.keys(condition).length
}
}
```Tests
```javascript
import { objectIncludes } from './objectIncludes.js'test('when true', () => {
const condition = { a: 1 }
const input = {
a: 1,
b: 2,
}const result = objectIncludes(condition)(input)
const expectedResult = trueexpect(result).toEqual(expectedResult)
})test('when false', () => {
const condition = { a: 1 }
const input = { b: 2 }const result = objectIncludes(condition)(input)
const expectedResult = falseexpect(result).toEqual(expectedResult)
})test('with nested object', () => {
const condition = { a: { b: 1 } }
const input = {
a: { b: 1 },
c: 2,
}const result = objectIncludes(condition)(input)
const expectedResult = trueexpect(result).toEqual(expectedResult)
})test('with wrong input', () => {
const condition = { a: { b: 1 } }expect(() => objectIncludes(condition)(null)).toThrowErrorMatchingInlineSnapshot(
`[TypeError: Cannot read properties of null (reading 'a')]`,
)
})
```TypeScript test
```typescript
import { objectIncludes, pipe } from 'rambda'describe('R.objectIncludes', () => {
it('happy', () => {
const result = pipe({ a: 1, b: 2, c: { d: 3 } }, objectIncludes({ a: 2 }))
result // $ExpectType boolean
})
it('nested', () => {
const result = pipe({ a: 1, b: 2, c: { d: 3 } }, objectIncludes({ c: { d: 3 } }))
result // $ExpectType boolean
})
})
```[](#objectIncludes)
### objOf
It creates an object with a single key-value pair.
```javascript
const result = R.objOf('foo')('bar')
// => {foo: 'bar'}
```Try this R.objOf example in Rambda REPL
[](#objOf)
### omit
```typescript
omit<
S extends string,
Keys extends PickStringToPickPath,
>(propsToPick: S): , any>>>(
obj: ElementOf extends keyof U ? U : never
) => ElementOf extends keyof U ? MergeTypes>> : never
```It returns a partial copy of an `obj` without `propsToOmit` properties.
```javascript
const obj = {a: 1, b: 2, c: 3}
const propsToOmit = 'a,c,d'
const propsToOmitList = ['a', 'c', 'd']const result = [
R.omit(propsToOmit, obj),
R.omit(propsToOmitList, obj)
]
// => [{b: 2}, {b: 2}]
```Try this R.omit example in Rambda REPL
All TypeScript definitions
```typescript
omit<
S extends string,
Keys extends PickStringToPickPath,
>(propsToPick: S): , any>>>(
obj: ElementOf extends keyof U ? U : never
) => ElementOf extends keyof U ? MergeTypes>> : never;
omit(propsToPick: Keys): <
U extends Partial, any>>
>(
obj: ElementOf extends keyof U ? U : never
) => ElementOf extends keyof U ? MergeTypes>> : never;
```R.omit source
```javascript
import { createPath } from './_internals/createPath.js'export function _includes(x, list) {
let index = -1
const { length } = listwhile (++index < length) {
if (String(list[index]) === String(x)) {
return true
}
}return false
}export function omit(propsToOmit) {
return obj => {
if (!obj) {
return undefined
}const propsToOmitValue = createPath(propsToOmit, ',')
const willReturn = {}for (const key in obj) {
if (!_includes(key, propsToOmitValue)) {
willReturn[key] = obj[key]
}
}return willReturn
}
}
```Tests
```javascript
import { omit } from './omit.js'test('with string as condition', () => {
const obj = {
a: 1,
b: 2,
c: 3,
}
const result = omit('a,c')(obj)
const expectedResult = { b: 2 }expect(result).toEqual(expectedResult)
})test('with array as condition', () => {
expect(
omit(['a', 'c', 'd'])({
a: 'foo',
b: 'bar',
c: 'baz',
}),
).toEqual({ b: 'bar' })
})
```TypeScript test
```typescript
import { omit, pipe } from 'rambda'const input = { a: 'foo', b: 2, c: 3 }
describe('R.omit', () => {
it('with string as input', () => {
const result = pipe(input, omit('a,b'))
result.c // $ExpectType number
})
it('with array as input', () => {
const result = pipe(input, omit(['a', 'b']))
result.c // $ExpectType number
})
})
```[](#omit)
### partition
```typescript
partition(
predicate: (value: T, index: number, data: ReadonlyArray) => value is S,
): (data: ReadonlyArray) => [Array, Array>]
```It will return array of two arrays according to `predicate` function. The first member holds all instances of `input` that pass the `predicate` function, while the second member - those who doesn't.
```javascript
const list = [1, 2, 3]
const predicate = x => x > 2const result = R.partition(predicate)(list)
const expected = [[3], [1, 2]]
// `result` is equal to `expected`
```Try this R.partition example in Rambda REPL
All TypeScript definitions
```typescript
partition(
predicate: (value: T, index: number, data: ReadonlyArray) => value is S,
): (data: ReadonlyArray) => [Array, Array>];
partition(
predicate: (value: T, index: number, data: ReadonlyArray) => boolean,
): (data: ReadonlyArray) => [Array, Array];
```R.partition source
```javascript
export function partition(predicate) {
return list => {
const yes = []
const no = []
let counter = -1
while (counter++ < list.length - 1) {
if (predicate(list[counter], counter)) {
yes.push(list[counter])
} else {
no.push(list[counter])
}
}
return [yes, no]
}
}
```Tests
```javascript
import { partition } from './partition.js'test('happy', () => {
const list = [1, 2, 3]
const predicate = x => x > 2const result = partition(predicate)(list)
expect(result).toEqual([[3], [1, 2]])
})
```TypeScript test
```typescript
import { partition, pipe } from 'rambda'describe('R.partition', () => {
it('happy', () => {
const predicate = (x: number) => {
return x > 2
}
const list = [1, 2, 3, 4]const result = pipe(list, partition(predicate))
result // $ExpectType [number[], number[]]
})
it('with simple object', () => {
const result = pipe(
[{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }],
partition(x => x.a > 2),
)
result // $ExpectType [{ a: number; }[], { a: number; }[]]
})
it('with complex object', () => {
interface Foo {
a: number
}
interface Bar {
b: number
}
const list1: (Foo | Bar)[] = [{ a: 1 }, { b: 2 }, { a: 3 }, { b: 4 }]
const filterFoo = (x: Foo | Bar): x is Foo => 'a' in x
const result = pipe(list1, partition(filterFoo))
result // $ExpectType [Foo[], Bar[]]
})
})
```[](#partition)
### partitionObject
```typescript
partitionObject(
predicate: (value: T, prop: string, obj: Record) => value is S,
): (obj: Record) => [Record, Record>]
```It returns an array containing two objects. The first object holds all properties of the input object for which the predicate returns true, while the second object holds those that do not.
```javascript
const obj = {a: 1, b: 2, c: 3}
const predicate = x => x > 2const result = R.partition(predicate)(obj)
const expected = [{c: 3}, {a: 1, b: 2}]
// `result` is equal to `expected`
```Try this R.partitionObject example in Rambda REPL
All TypeScript definitions
```typescript
partitionObject(
predicate: (value: T, prop: string, obj: Record) => value is S,
): (obj: Record) => [Record, Record>];
partitionObject(
predicate: (value: T, prop: string, obj: Record) => boolean,
): (obj: Record) => [Record, Record];
```R.partitionObject source
```javascript
export function partitionObject(predicate) {
return obj => {
const yes = {}
const no = {}
Object.entries(obj).forEach(([prop, value]) => {
if (predicate(value, prop)) {
yes[prop] = value
} else {
no[prop] = value
}
})return [yes, no]
}
}
```Tests
```javascript
import { partitionObject } from './partitionObject.js'test('happy', () => {
const predicate = (value, prop) => {
expect(typeof prop).toBe('string')return value > 2
}
const hash = {
a: 1,
b: 2,
c: 3,
d: 4,
}const result = partitionObject(predicate)(hash)
const expectedResult = [
{
c: 3,
d: 4,
},
{
a: 1,
b: 2,
},
]expect(result).toEqual(expectedResult)
})
```TypeScript test
```typescript
import { partitionObject, pipe } from 'rambda'describe('R.partition', () => {
it('happy', () => {
let result = pipe(
{ a: 1, b: 2 },
partitionObject((x, prop) => x> 1 || prop === 'c'),
)
result // $ExpectType [Record, Record]
})
it('with complex object', () => {
interface Foo {
a: number
}
interface Bar {
b: number
}
const obj: Record = {
a: { a: 1 },
b: { b: 2 },
c: { a: 3 },
d: { b: 4 },
}
const filterFoo = (x: Foo | Bar): x is Foo => 'a' in x
const result = pipe(obj, partitionObject(filterFoo))
result // $ExpectType [Record, Record]
})
})
```[](#partitionObject)
### path
```typescript
path(path: `${K0}`): (obj: S) => S[K0]
```If `pathToSearch` is `'a.b'` then it will return `1` if `obj` is `{a:{b:1}}`.
It will return `undefined`, if such path is not found.
> :boom: String annotation of `pathToSearch` is one of the differences between `Rambda` and `Ramda`.
```javascript
const obj = {a: {b: 1}}
const pathToSearch = 'a.b'
const pathToSearchList = ['a', 'b']const result = [
R.path(pathToSearch, obj),
R.path(pathToSearchList, obj),
R.path('a.b.c.d', obj)
]
// => [1, 1, undefined]
```Try this R.path example in Rambda REPL
All TypeScript definitions
```typescript
path(path: `${K0}`): (obj: S) => S[K0];
path(path: `${K0}.${K1}`): (obj: S) => S[K0][K1];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1]
>(path: [K0, K1, K2]): (obj: S) => S[K0][K1][K2];
path<
S,
K0 extends string & keyof S,
K1 extends string & keyof S[K0],
K2 extends string & keyof S[K0][K1]
>(path: `${K0}.${K1}.${K2}`): (obj: S) => S[K0][K1][K2];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2]
>(path: [K0, K1, K2, K3]): (obj: S) => S[K0][K1][K2][K3];
path<
S,
K0 extends string & keyof S,
K1 extends string & keyof S[K0],
K2 extends string & keyof S[K0][K1],
K3 extends string & keyof S[K0][K1][K2]
>(path: `${K0}.${K1}.${K2}.${K3}`): (obj: S) => S[K0][K1][K2][K3];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3]
>(path: [K0, K1, K2, K3, K4]): (obj: S) => S[K0][K1][K2][K3][K4];
path<
S,
K0 extends string & keyof S,
K1 extends string & keyof S[K0],
K2 extends string & keyof S[K0][K1],
K3 extends string & keyof S[K0][K1][K2],
K4 extends string & keyof S[K0][K1][K2][K3]
>(path: `${K0}.${K1}.${K2}.${K3}.${K4}`): (obj: S) => S[K0][K1][K2][K3][K4];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3]
>(path: [K0, K1, K2, K3, K4], obj: S): S[K0][K1][K2][K3][K4];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4]
>(path: [K0, K1, K2, K3, K4, K5]): (obj: S) => S[K0][K1][K2][K3][K4][K5];
path<
S,
K0 extends string & keyof S,
K1 extends string & keyof S[K0],
K2 extends string & keyof S[K0][K1],
K3 extends string & keyof S[K0][K1][K2],
K4 extends string & keyof S[K0][K1][K2][K3],
K5 extends string & keyof S[K0][K1][K2][K3][K4]
>(path: `${K0}.${K1}.${K2}.${K3}.${K4}.${K5}`): (obj: S) => S[K0][K1][K2][K3][K4][K5];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4]
>(path: [K0, K1, K2, K3, K4, K5], obj: S): S[K0][K1][K2][K3][K4][K5];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4],
K6 extends keyof S[K0][K1][K2][K3][K4][K5]
>(path: [K0, K1, K2, K3, K4, K5, K6]): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6];
path<
S,
K0 extends string & keyof S,
K1 extends string & keyof S[K0],
K2 extends string & keyof S[K0][K1],
K3 extends string & keyof S[K0][K1][K2],
K4 extends string & keyof S[K0][K1][K2][K3],
K5 extends string & keyof S[K0][K1][K2][K3][K4],
K6 extends string & keyof S[K0][K1][K2][K3][K4][K5]
>(path: `${K0}.${K1}.${K2}.${K3}.${K4}.${K5}.${K6}`): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4],
K6 extends keyof S[K0][K1][K2][K3][K4][K5]
>(path: [K0, K1, K2, K3, K4, K5, K6], obj: S): S[K0][K1][K2][K3][K4][K5][K6];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4],
K6 extends keyof S[K0][K1][K2][K3][K4][K5],
K7 extends keyof S[K0][K1][K2][K3][K4][K5][K6]
>(path: [K0, K1, K2, K3, K4, K5, K6, K7]): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6][K7];
path<
S,
K0 extends string & keyof S,
K1 extends string & keyof S[K0],
K2 extends string & keyof S[K0][K1],
K3 extends string & keyof S[K0][K1][K2],
K4 extends string & keyof S[K0][K1][K2][K3],
K5 extends string & keyof S[K0][K1][K2][K3][K4],
K6 extends string & keyof S[K0][K1][K2][K3][K4][K5],
K7 extends string & keyof S[K0][K1][K2][K3][K4][K5][K6]
>(path: `${K0}.${K1}.${K2}.${K3}.${K4}.${K5}.${K6}.${K7}`): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6][K7];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4],
K6 extends keyof S[K0][K1][K2][K3][K4][K5],
K7 extends keyof S[K0][K1][K2][K3][K4][K5][K6],
K8 extends keyof S[K0][K1][K2][K3][K4][K5][K6][K7]
>(path: [K0, K1, K2, K3, K4, K5, K6, K7, K8]): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6][K7][K8];
path<
S,
K0 extends string & keyof S,
K1 extends string & keyof S[K0],
K2 extends string & keyof S[K0][K1],
K3 extends string & keyof S[K0][K1][K2],
K4 extends string & keyof S[K0][K1][K2][K3],
K5 extends string & keyof S[K0][K1][K2][K3][K4],
K6 extends string & keyof S[K0][K1][K2][K3][K4][K5],
K7 extends string & keyof S[K0][K1][K2][K3][K4][K5][K6],
K8 extends string & keyof S[K0][K1][K2][K3][K4][K5][K6][K7]
>(path: `${K0}.${K1}.${K2}.${K3}.${K4}.${K5}.${K6}.${K7}.${K8}`): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6][K7][K8];
path(path: [K0]): (obj: S) => S[K0];
path(path: [K0, K1]): (obj: S) => S[K0][K1];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1]
>(path: [K0, K1, K2]): (obj: S) => S[K0][K1][K2];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2]
>(path: [K0, K1, K2, K3]): (obj: S) => S[K0][K1][K2][K3];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3]
>(path: [K0, K1, K2, K3, K4]): (obj: S) => S[K0][K1][K2][K3][K4];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3]
>(path: [K0, K1, K2, K3, K4], obj: S): S[K0][K1][K2][K3][K4];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4]
>(path: [K0, K1, K2, K3, K4, K5]): (obj: S) => S[K0][K1][K2][K3][K4][K5];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4]
>(path: [K0, K1, K2, K3, K4, K5], obj: S): S[K0][K1][K2][K3][K4][K5];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4],
K6 extends keyof S[K0][K1][K2][K3][K4][K5]
>(path: [K0, K1, K2, K3, K4, K5, K6]): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4],
K6 extends keyof S[K0][K1][K2][K3][K4][K5]
>(path: [K0, K1, K2, K3, K4, K5, K6], obj: S): S[K0][K1][K2][K3][K4][K5][K6];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4],
K6 extends keyof S[K0][K1][K2][K3][K4][K5],
K7 extends keyof S[K0][K1][K2][K3][K4][K5][K6]
>(path: [K0, K1, K2, K3, K4, K5, K6, K7]): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6][K7];
path<
S,
K0 extends keyof S,
K1 extends keyof S[K0],
K2 extends keyof S[K0][K1],
K3 extends keyof S[K0][K1][K2],
K4 extends keyof S[K0][K1][K2][K3],
K5 extends keyof S[K0][K1][K2][K3][K4],
K6 extends keyof S[K0][K1][K2][K3][K4][K5],
K7 extends keyof S[K0][K1][K2][K3][K4][K5][K6],
K8 extends keyof S[K0][K1][K2][K3][K4][K5][K6][K7]
>(path: [K0, K1, K2, K3, K4, K5, K6, K7, K8]): (obj: S) => S[K0][K1][K2][K3][K4][K5][K6][K7][K8];
```R.path source
```javascript
import { createPath } from './_internals/createPath.js'export function path(pathInput, obj) {
if (arguments.length === 1) {
return _obj => path(pathInput, _obj)
}if (!obj) {
return undefined
}
let willReturn = obj
let counter = 0const pathArrValue = createPath(pathInput)
while (counter < pathArrValue.length) {
if (willReturn === null || willReturn === undefined) {
return undefined
}
if (willReturn[pathArrValue[counter]] === null) {
return undefined
}willReturn = willReturn[pathArrValue[counter]]
counter++
}return willReturn
}
```Tests
```javascript
import { path } from './path.js'test('with array inside object', () => {
const obj = { a: { b: [1, { c: 1 }] } }expect(path('a.b.1.c', obj)).toBe(1)
})test('works with undefined', () => {
const obj = { a: { b: { c: 1 } } }expect(path('a.b.c.d.f', obj)).toBeUndefined()
expect(path('foo.babaz', undefined)).toBeUndefined()
expect(path('foo.babaz')(undefined)).toBeUndefined()
})test('works with string instead of array', () => {
expect(path('foo.bar.baz')({ foo: { bar: { baz: 'yes' } } })).toBe('yes')
})test('path', () => {
expect(path(['foo', 'bar', 'baz'])({ foo: { bar: { baz: 'yes' } } })).toBe('yes')
expect(path(['foo', 'bar', 'baz'])(null)).toBeUndefined()
expect(path(['foo', 'bar', 'baz'])({ foo: { bar: 'baz' } })).toBeUndefined()
})test('with number string in between', () => {
expect(path(['a', '1', 'b'], { a: [{ b: 1 }, { b: 2 }] })).toBe(2)
})test('null is not a valid path', () => {
expect(
path('audio_tracks', {
a: 1,
audio_tracks: null,
}),
).toBeUndefined()
})
```TypeScript test
```typescript
import { path, pipe } from 'rambda'const input = { a: { b: { c: true } } }
describe('R.path with string as path', () => {
it('happy', () => {
const result = pipe(input, path(['a', 'b']))
const resultStringInput = pipe(input, path('a.b.c'))
result.c // $ExpectType boolean
resultStringInput // $ExpectType boolean
})
it('happy', () => {
const result = pipe([1, 2, 3], path([1]))
result // $ExpectType number
})
})
```[](#path)
### permutations
```typescript
permutations(list: T[]): T[][]
``````javascript
const result = R.permutations(
[1, 2]
)
// => [[1, 2], [2, 1]]
```Try this R.permutations example in Rambda REPL
All TypeScript definitions
```typescript
permutations(list: T[]): T[][];
```R.permutations source
```javascript
import { cloneList } from './_internals/cloneList.js'/**
* Source:
* https://github.com/denoland/std/blob/main/collections/permutations.ts
*/
export function permutations(inputArray) {
const result = [];
const array = cloneList(inputArray);
const k = array.length;
if (k === 0) {
return result;
}const c = new Array(k).fill(0);
result.push([...array]);
let i = 1;
while (i < k) {
if (c[i] < i) {
if (i % 2 === 0) {
[array[0], array[i]] = [array[i], array[0]]
} else {
[array[c[i]], array[i]] = [array[i], array[c[i]]]
}result.push([...array]);
c[i] += 1;
i = 1;
} else {
c[i] = 0;
i += 1;
}
}return result;
}
```[](#permutations)
### pick
```typescript
pick(propsToPick: K[]): (input: T) => MergeTypes>>>
```It returns a partial copy of an `input` containing only `propsToPick` properties.
`input` can be either an object or an array.
String annotation of `propsToPick` is one of the differences between `Rambda` and `Ramda`.
> :boom: Typescript Note: Pass explicit type annotation when used with **R.pipe/R.compose** for better type inference
```javascript
const obj = {
a : 1,
b : false,
foo: 'cherry'
}
const propsToPick = 'a,foo'
const propsToPickList = ['a', 'foo']const result = [
R.pick(propsToPick)(obj),
R.pick(propsToPickList)(obj),
R.pick('a,bar')(obj),
R.pick('bar')(obj),
]const expected = [
{a:1, foo: 'cherry'},
{a:1, foo: 'cherry'},
{a:1},
{},
]
// => `result` is equal to `expected`
```Try this R.pick example in Rambda REPL
All TypeScript definitions
```typescript
pick(propsToPick: K[]): (input: T) => MergeTypes>>>;
pick<
S extends string,
K extends PickStringToPickPath
>(propsToPick: S): (input: T) => MergeTypes>>>;
```R.pick source
```javascript
import { createPath } from './_internals/createPath.js'export function pick(propsToPick) {
return input => {
if (!input === null) {
return undefined
}
const keys = createPath(propsToPick, ',')
const willReturn = {}
let counter = 0while (counter < keys.length) {
if (keys[counter] in input) {
willReturn[keys[counter]] = input[keys[counter]]
}
counter++
}return willReturn
}
}
```Tests
```javascript
import { pick } from './pick.js'const obj = {
a: 1,
b: 2,
c: 3,
}test('props to pick is a string', () => {
const result = pick('a,c')(obj)
const expectedResult = {
a: 1,
c: 3,
}expect(result).toEqual(expectedResult)
})test('when prop is missing', () => {
const result = pick('a,d,f')(obj)
expect(result).toEqual({ a: 1 })
})test('props to pick is an array', () => {
expect(
pick(['a', 'c'])({
a: 'foo',
b: 'bar',
}),
).toEqual({
a: 'foo',
})
})
```TypeScript test
```typescript
import { pick, pipe } from 'rambda'const input = { a: 'foo', c: 3 }
describe('R.pick', () => {
it('with string as input', () => {
const result = pipe(input, pick('a,c,b,o'))
result.a // $ExpectType string
result.c // $ExpectType number
})
it('with array as input', () => {
const result = pipe(input, pick(['a', 'c']))
result.a // $ExpectType string
result.c // $ExpectType number
})
})
```[](#pick)
### pipe
It performs left-to-right function composition, where first argument is the input for the chain of functions.
This is huge difference from `Ramda.pipe` where input is passed like `R.pipe(...fns)(input)`.
Here we have `R.pipe(input, ...fns)`.It has much better TypeScript support than `Ramda.pipe` and this is the reason why `Rambda` goes in this direction.
```javascript
const result = R.pipe(
[1, 2, 3],
R.filter(x => x > 1),
R.map(x => x*10),
)
// => [20, 30]
```Try this R.pipe example in Rambda REPL
[](#pipe)
### pipeAsync
It accepts input as first argument and series of functions as next arguments. It is same as `R.pipe` but with support for asynchronous functions.
```javascript
const result = await R.pipeAsync(
100,
async x => {
await R.delay(100)
return x + 2
},
R.add(2),
async x => {
const delayed = await R.delay(100)
return delayed + x
}
)
// `result` resolves to `RAMBDAX_DELAY104`
```Try this R.pipeAsync example in Rambda REPL
[](#pipeAsync)
### pluck
```typescript
pluck(property: K): (list: T[]) => T[K][]
```It returns list of the values of `property` taken from the all objects inside `list`.
Basically, this is `R.map(R.prop(property))`.> :boom: Typescript Note: Pass explicit type annotation when used with **R.pipe/R.compose** for better type inference
```javascript
const list = [{a: 1}, {a: 2}, {b: 3}]
const property = 'a'const result = R.pluck(property)(list)
// => [1, 2]
```Try this R.pluck example in Rambda REPL
All TypeScript definitions
```typescript
pluck(property: K): (list: T[]) => T[K][];
```R.pluck source
```javascript
export function pluck(property) {
return list => {
const willReturn = []list.forEach(x => {
if (x[property] !== undefined) {
willReturn.push(x[property])
}
})return willReturn
}
}
```Tests
```javascript
import { pluck } from './pluck.js'test('happy', () => {
expect(pluck('a')([{ a: 1 }, { a: 2 }, { b: 1 }])).toEqual([1, 2])
})test('with undefined', () => {
expect(pluck(undefined)([{ a: 1 }, { a: 2 }, { b: 1 }])).toEqual([])
})
```TypeScript test
```typescript
import { pipe, pluck } from 'rambda'it('R.pluck', () => {
const input = [
{ a: 1, b: 'foo' },
{ a: 2, b: 'bar' },
]
const result = pipe(input, pluck('b'))
result // $ExpectType string[]
})
```[](#pluck)
### prepend
```typescript
prepend(xToPrepend: T, iterable: T[]): T[]
```It adds element `x` at the beginning of `list`.
```javascript
const result = R.prepend('foo', ['bar', 'baz'])
// => ['foo', 'bar', 'baz']
```Try this R.prepend example in Rambda REPL
All TypeScript definitions
```typescript
prepend(xToPrepend: T, iterable: T[]): T[];
prepend(xToPrepend: T): (iterable: T[]) => T[];
```R.prepend source
```javascript
export function prepend(x) {
return list => [x].concat(list)
}
```Tests
```javascript
import { prepend } from './prepend.js'test('happy', () => {
expect(prepend('yes')(['foo', 'bar', 'baz'])).toEqual(['yes', 'foo', 'bar', 'baz'])
})test('with empty list', () => {
expect(prepend('foo')([])).toEqual(['foo'])
})
```[](#prepend)
### prop
```typescript
prop(prop: K): (obj: U) => U[K]
```It returns the value of property `propToFind` in `obj`.
If there is no such property, it returns `undefined`.
```javascript
const result = [
R.prop('x')({x: 100}),
R.prop('x')({a: 1})
]
// => [100, undefined]
```Try this R.prop example in Rambda REPL
All TypeScript definitions
```typescript
prop(prop: K): (obj: U) => U[K];
prop(prop: K, obj: U): U[K];
```R.prop source
```javascript
export function prop(searchProperty) {
return obj => (obj ? obj[searchProperty] : undefined)
}
```TypeScript test
```typescript
import { map, pipe, prop } from 'rambda'describe('R.prop', () => {
it('happy', () => {
const result = pipe({ a: 1 }, prop('a'))result // $ExpectType number
})
it('alike R.pluck', () => {
const result = pipe([{ a: 1 }, { a: 2 }], map(prop('a')))result // $ExpectType number[]
})
})
```[](#prop)
### propEq
```typescript
propEq(val: T): {
(name: K): (obj: Record) => boolean
```It returns true if `obj` has property `propToFind` and its value is equal to `valueToMatch`.
```javascript
const obj = { foo: 'bar' }
const secondObj = { foo: 1 }const propToFind = 'foo'
const valueToMatch = 'bar'const result = [
R.propEq(propToFind, valueToMatch)(obj),
R.propEq(propToFind, valueToMatch)(secondObj)
]
// => [true, false]
```Try this R.propEq example in Rambda REPL
All TypeScript definitions
```typescript
propEq(val: T): {
(name: K): (obj: Record) => boolean;
(name: K, obj: Record): boolean;
};
propEq(val: T, name: K): (obj: Record) => boolean;
propEq(val: U[K], name: K, obj: U): boolean;
```R.propEq source
```javascript
import { equalsFn } from './equals.js'export function propEq(valueToMatch, propToFind) {
return obj => {
if (!obj) {
return false
}return equalsFn(valueToMatch, obj[propToFind])
}
}
```Tests
```javascript
import { propEq } from './propEq.js'const FOO = 'foo'
const BAR = 'bar'test('happy', () => {
const obj = { [FOO]: BAR }
expect(propEq(BAR, FOO)(obj)).toBeTruthy()
expect(propEq(1, FOO)(obj)).toBeFalsy()
expect(propEq(1, 1)(null)).toBeFalsy()
})test('returns false if called with a null or undefined object', () => {
expect(propEq('name', 'Abby')(null)).toBeFalsy()
expect(propEq('name', 'Abby')(undefined)).toBeFalsy()
})
```[](#propEq)
### propOr
```typescript
propOr(defaultValue: T, property: P): (obj: Partial>) => T
```It returns either `defaultValue` or the value of `property` in `obj`.
```javascript
const obj = {a: 1}
const defaultValue = 'DEFAULT_VALUE'
const property = 'a'const result = [
R.propOr(defaultValue, property)(obj),
R.propOr(defaultValue, 'foo')(obj)
]
// => [1, 'DEFAULT_VALUE']
```Try this R.propOr example in Rambda REPL
All TypeScript definitions
```typescript
propOr(defaultValue: T, property: P): (obj: Partial>) => T;
```R.propOr source
```javascript
import { defaultTo } from './defaultTo.js'export function propOr(defaultValue, property) {
return obj => {
if (!obj) {
return defaultValue
}return defaultTo(defaultValue, obj[property])
}
}
```Tests
```javascript
import { propOr } from './propOr.js'test('propOr', () => {
const obj = { a: 1 }
expect(propOr('default', 'a')(obj)).toBe(1)
expect(propOr('default', 'notExist')(obj)).toBe('default')
expect(propOr('default', 'notExist')(null)).toBe('default')
})
```TypeScript test
```typescript
import { propOr } from 'rambda'const obj = { foo: 'bar' }
const property = 'foo'
const fallback = 'fallback'describe('R.propOr', () => {
it('happy', () => {
const result = propOr(fallback, property)(obj)
result // $ExpectType string
})
})
```[](#propOr)
### propSatisfies
```typescript
propSatisfies(predicate: (x: T) => boolean, property: string): (obj: Record) => boolean
```It returns `true` if the object property satisfies a given predicate.
```javascript
const obj = {a: {b:1}}
const property = 'a'
const predicate = x => x?.b === 1const result = R.propSatisfies(predicate, property, obj)
// => true
```Try this R.propSatisfies example in Rambda REPL
All TypeScript definitions
```typescript
propSatisfies(predicate: (x: T) => boolean, property: string): (obj: Record) => boolean;
```R.propSatisfies source
```javascript
export function propSatisfies(predicate, property) {
return obj => predicate(obj[property])
}
```Tests
```javascript
import { propSatisfies } from './propSatisfies.js'const obj = { a: 1 }
test('when true', () => {
expect(propSatisfies(x => x > 0, 'a')(obj)).toBeTruthy()
})test('when false', () => {
expect(propSatisfies(x => x < 0, 'a')(obj)).toBeFalsy()
})
```TypeScript test
```typescript
import { pipe, propSatisfies } from 'rambda'const obj = { a: 1 }
describe('R.propSatisfies', () => {
it('happy', () => {
const result = pipe(
obj,
propSatisfies(x => {
x // $ExpectType number
return x > 0
}, 'a'),
)result // $ExpectType boolean
})
})
```[](#propSatisfies)
### range
```typescript
range(startInclusive: number): (endExclusive: number) => number[]
```It returns list of numbers between `startInclusive` to `endInclusive` markers.
```javascript
R.range(0)(5)
// => [0, 1, 2, 3, 4, 5]
```Try this R.range example in Rambda REPL
All TypeScript definitions
```typescript
range(startInclusive: number): (endExclusive: number) => number[];
```R.range source
```javascript
export function range(start) {
return end => {
if (Number.isNaN(Number(start)) || Number.isNaN(Number(end))) {
throw new TypeError('Both arguments to range must be numbers')
}if (end <= start) {
return []
}const len = end - start
const willReturn = Array(len)for (let i = 0; i < len + 1; i++) {
willReturn[i] = start + i
}return willReturn
}
}export function rangeDescending(start) {
return end => {
if (Number.isNaN(Number(start)) || Number.isNaN(Number(end))) {
throw new TypeError('Both arguments to range must be numbers')
}if (end >= start) {
return []
}const len = start - end
const willReturn = Array(len)for (let i = 0; i < len + 1; i++) {
willReturn[i] = start - i
}return willReturn
}
}
```Tests
```javascript
import { range, rangeDescending } from './range.js'test('happy', () => {
expect(range(0)(10)).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
})test('end range is bigger than start range', () => {
expect(range(7)(3)).toEqual([])
expect(range(5)(5)).toEqual([])
})test('descending', () => {
expect(rangeDescending(5)(0)).toEqual([5, 4, 3, 2, 1, 0])
})test('descending end range is bigger than start range', () => {
expect(rangeDescending(3)(7)).toEqual([])
expect(rangeDescending(5)(5)).toEqual([])
})
```TypeScript test
```typescript
import { range } from 'rambda'describe('R.range', () => {
it('curried', () => {
const result = range(1)(4)result // $ExpectType number[]
})
})
```[](#range)
### rangeDescending
```typescript
rangeDescending(startInclusive: number): (endExclusive: number) => number[]
```Same as `R.range` but in descending order.
```javascript
R.rangeDescending(5, 0)
// => [5, 4, 3, 2, 1, 0]
```Try this R.rangeDescending example in Rambda REPL
All TypeScript definitions
```typescript
rangeDescending(startInclusive: number): (endExclusive: number) => number[];
```[](#rangeDescending)
### reduce
> :boom: It passes index of the list as third argument to `reducer` function.
```javascript
const list = [1, 2, 3]
const initialValue = 10
const reducer = (prev, current) => prev * currentconst result = R.reduce(reducer, initialValue, list)
// => 60
```Try this R.reduce example in Rambda REPL
[](#reduce)
### reject
```typescript
reject(
predicate: (value: T) => boolean,
list: T[],
): T[]
```It has the opposite effect of `R.filter`.
```javascript
const list = [1, 2, 3, 4]
const obj = {a: 1, b: 2}
const predicate = x => x > 1const result = [
R.reject(predicate)(list),
R.reject(predicate)(obj)
]
// => [[1], {a: 1}]
```Try this R.reject example in Rambda REPL
All TypeScript definitions
```typescript
reject(
predicate: (value: T) => boolean,
list: T[],
): T[];
reject(
predicate: BooleanConstructor,
): (list: readonly T[]) => ("" | null | undefined | false | 0)[];
reject(
predicate: BooleanConstructor,
): (list: T[]) => ("" | null | undefined | false | 0)[];
reject(
predicate: (value: T) => boolean,
): (list: T[]) => T[];
```R.reject source
```javascript
import { filter } from './filter.js'export function reject(predicate) {
return list => filter(x => !predicate(x))(list)
}
```Tests
```javascript
import { reject } from './reject.js'test('happy', () => {
const isEven = n => n % 2 === 0expect(reject(isEven)([1, 2, 3, 4])).toEqual([1, 3])
})
```TypeScript test
```typescript
import { reject, pipe } from 'rambda'const list = [1, 2, 3]
describe('R.reject with array', () => {
it('within pipe', () => {
const result = pipe(
list,
reject(x => {
x // $ExpectType number
return x > 1
}),
)
result // $ExpectType number[]
})
it('narrowing type', () => {
interface Foo {
a: number
}
interface Bar extends Foo {
b: string
}
interface Baz extends Foo {
c: string
}const testList: (Foo | Bar | Baz)[] = [{ a: 1 }, { a: 2 }, { a: 3 }]
const rejectBar = (x: Foo | Bar | Baz): x is Bar => {
return typeof (x as Bar).b === 'string'
}
const result = pipe(
testList,
reject(rejectBar),
)
result // $ExpectType (Foo | Baz)[]
})
it('narrowing type - readonly', () => {
interface Foo {
a: number
}
interface Bar extends Foo {
b: string
}
interface Baz extends Foo {
c: string
}const testList: (Foo | Bar | Baz)[] = [{ a: 1 }, { a: 2 }, { a: 3 }] as const
const rejectBar = (x: Foo | Bar | Baz): x is Bar => {
return typeof (x as Bar).b === 'string'
}
const result = pipe(
testList,
reject(rejectBar),
)
result // $ExpectType (Foo | Baz)[]
})
it('rejecting NonNullable', () => {
const testList = [1, 2, null, undefined, 3]
const result = pipe(testList, reject(Boolean))
result // $ExpectType (null | undefined)[]
})
it('rejecting NonNullable - readonly', () => {
const testList = [1, 2, null, undefined, 3] as const
const result = pipe(testList, reject(Boolean))
result // $ExpectType (null | undefined)[]
// @ts-expect-error
result.includes(1)
})
})
```[](#reject)
### rejectObject
```typescript
rejectObject(
valueMapper: (
value: EnumerableStringKeyedValueOf,
key: EnumerableStringKeyOf,
data: T,
) => boolean,
): (data: T) => U
```Same as `R.filterObject` but it returns the object with properties that do not satisfy the predicate function.
```javascript
const result = R.rejectObject(
(val, prop) => prop === 'a' || val > 1
)({a: 1, b: 2, c:3})
// => {b: 2}
```Try this R.rejectObject example in Rambda REPL
All TypeScript definitions
```typescript
rejectObject(
valueMapper: (
value: EnumerableStringKeyedValueOf,
key: EnumerableStringKeyOf,
data: T,
) => boolean,
): (data: T) => U;
```R.rejectObject source
```javascript
export function rejectObject(predicate) {
return obj => {
const willReturn = {}for (const prop in obj) {
if (!predicate(obj[prop], prop, obj)) {
willReturn[prop] = obj[prop]
}
}return willReturn
}
}
```Tests
```javascript
import { pipe } from './pipe.js'
import { rejectObject } from './rejectObject.js'test('happy', () => {
let testInput = { a: 1, b: 2, c: 3 }
const result = pipe(
testInput,
rejectObject((x, prop, obj) => {
expect(prop).toBeOneOf(['a', 'b', 'c'])
expect(obj).toBe(testInput)
return x > 1
})
)
expect(result).toEqual({ a:1 })
})
```TypeScript test
```typescript
import { filterObject, pipe } from 'rambda'describe('R.filterObject', () => {
it('require explicit type', () => {
const result = pipe(
{ a: 1, b: 2 },
filterObject<{ b: number }>(a => {
a // $ExpectType number
return a > 1
}),
)
result.b // $ExpectType number
})
})
```[](#rejectObject)
### replace
```typescript
replace(strOrRegex: RegExp | string, replacer: RegExp | string): (str: string) => string
```It replaces `strOrRegex` found in `str` with `replacer`.
```javascript
const result = [
R.replace('o', '|1|')('foo'),
R.replace(/o/g, '|1|')('foo'),
]
// => ['f|1|o', 'f|1||1|']
```Try this R.replace example in Rambda REPL
All TypeScript definitions
```typescript
replace(strOrRegex: RegExp | string, replacer: RegExp | string): (str: string) => string;
```R.replace source
```javascript
export function replace(pattern, replacer) {
return str => str.replace(pattern, replacer)
}
```Tests
```javascript
import { replace } from './replace.js'test('happy', () => {
expect(replace(/\s/g, '|')('foo bar baz')).toBe('foo|bar|baz')
expect(replace('a', '|')('foo bar baz')).toBe('foo b|r baz')
})
```TypeScript test
```typescript
import { replace } from 'rambda'const str = 'foo bar foo'
const replacer = 'bar'describe('R.replace', () => {
it('happy', () => {
const result = replace(/foo/g, replacer)(str)result // $ExpectType string
})
it('with string as search pattern', () => {
const result = replace('foo', replacer)(str)result // $ExpectType string
})
})
```[](#replace)
### replaceItemAtIndex
```typescript
replaceItemAtIndex(index: number, replaceFn: (x: T) => T): (list: T[]) => T[]
```It replaces `index` in array `list` with the result of `replaceFn(list[i])`.
```javascript
const result = R.pipe(
[1, 2, 3],
R.replaceItemAtIndex(1, R.add(1))
) // => [1, 3, 3]
```Try this R.replaceItemAtIndex example in Rambda REPL
All TypeScript definitions
```typescript
replaceItemAtIndex(index: number, replaceFn: (x: T) => T): (list: T[]) => T[];
```R.replaceItemAtIndex source
```javascript
import { cloneList } from './_internals/cloneList.js'export function replaceItemAtIndex(index, replaceFn) {
return list => {
const actualIndex = index < 0 ? list.length + index : index
if (index >= list.length || actualIndex < 0) {
return list
}const clone = cloneList(list)
clone[actualIndex] = replaceFn(clone[actualIndex])return clone
}
}
```Tests
```javascript
import { replaceItemAtIndex } from './replaceItemAtIndex.js'const add10 = x => x + 10
const list = [0, 1, 2]
const expected = [0, 11, 2]test('happy', () => {
expect(replaceItemAtIndex(1, add10)(list)).toEqual(expected)
})test('with negative index', () => {
expect(replaceItemAtIndex(-2, add10)(list)).toEqual(expected)
})test('when index is out of bounds', () => {
const list = [0, 1, 2, 3]
expect(replaceItemAtIndex(4, add10)(list)).toEqual(list)
expect(replaceItemAtIndex(-5, add10)(list)).toEqual(list)
})
```[](#replaceItemAtIndex)
### shuffle
```typescript
shuffle(list: T[]): T[]
```It returns a randomized copy of array.
```javascript
const result = R.shuffle(
[1, 2, 3]
)
// => [3, 1, 2] or [2, 3, 1] or ...
```Try this R.shuffle example in Rambda REPL
All TypeScript definitions
```typescript
shuffle(list: T[]): T[];
```R.shuffle source
```javascript
export function shuffle(listInput) {
const list = cloneList(listInput)
let counter = list.length
while (counter > 0) {
const index = Math.floor(Math.random() * counter)
counter--
const temp = list[counter]
list[counter] = list[index]
list[index] = temp
}return list
}
```TypeScript test
```typescript
import { shuffle } from 'rambdax'const list = [1, 2, 3, 4, 5]
describe('R.shuffle', () => {
it('happy', () => {
const result = shuffle(list)
result // $ExpectType number[]
})
})
```[](#shuffle)
### sort
```typescript
sort(sortFn: (a: T, b: T) => number): (list: T[]) => T[]
```It returns copy of `list` sorted by `sortFn` function, where `sortFn` needs to return only `-1`, `0` or `1`.
```javascript
const list = [
{a: 2},
{a: 3},
{a: 1}
]
const sortFn = (x, y) => {
return x.a > y.a ? 1 : -1
}const result = R.sort(sortFn, list)
const expected = [
{a: 1},
{a: 2},
{a: 3}
]
// => `result` is equal to `expected`
```Try this R.sort example in Rambda REPL
All TypeScript definitions
```typescript
sort(sortFn: (a: T, b: T) => number): (list: T[]) => T[];
```R.sort source
```javascript
import { cloneList } from './_internals/cloneList.js'export function sort(sortFn) {
return list => cloneList(list).sort(sortFn)
}
```Tests
```javascript
import { sort } from './sort.js'const fn = (a, b) => (a > b ? 1 : -1)
test('sort', () => {
expect(sort((a, b) => a - b)([2, 3, 1])).toEqual([1, 2, 3])
})test("it doesn't mutate", () => {
const list = ['foo', 'bar', 'baz']expect(sort(fn)(list)).toEqual(['bar', 'baz', 'foo'])
expect(list).toEqual(['foo', 'bar', 'baz'])
})
```TypeScript test
```typescript
import { pipe, sort } from 'rambda'const list = [3, 0, 5, 2, 1]
describe('R.sort', () => {
it('happy', () => {
const result = sort((a, b) => {
return a > b ? 1 : -1
})(list)
result // $ExpectType number[]
})
it('within pipe', () => {
const result = pipe(
list,
sort((a, b) => {
return a > b ? 1 : -1
}),
)
result // $ExpectType number[]
})
})
```[](#sort)
### sortBy
```typescript
sortBy(sortFn: (x: T) => Ord): (list: T[]) => T[]
```It returns copy of `list` sorted by `sortFn` function, where `sortFn` function returns a value to compare, i.e. it doesn't need to return only `-1`, `0` or `1`.
```javascript
const list = [
{a: 2},
{a: 3},
{a: 1}
]
const sortFn = x => x.aconst result = R.sortBy(sortFn, list)
const expected = [
{a: 1},
{a: 2},
{a: 3}
]
// => `result` is equal to `expected`
```Try this R.sortBy example in Rambda REPL
All TypeScript definitions
```typescript
sortBy(sortFn: (x: T) => Ord): (list: T[]) => T[];
```R.sortBy source
```javascript
import { cloneList } from './_internals/cloneList.js'export function sortBy(sortFn) {
return list => {
const clone = cloneList(list)return clone.sort((a, b) => {
const aSortResult = sortFn(a)
const bSortResult = sortFn(b)if (aSortResult === bSortResult) {
return 0
}return aSortResult < bSortResult ? -1 : 1
})
}
}
```Tests
```javascript
import { sortBy } from './sortBy.js'test('happy', () => {
const input = [{ a: 2 }, { a: 1 }, { a: 1 }, { a: 3 }]
const expected = [{ a: 1 }, { a: 1 }, { a: 2 }, { a: 3 }]const result = sortBy(x => x.a)(input)
expect(result).toEqual(expected)
})
```TypeScript test
```typescript
import { pipe, sortBy } from 'rambda'describe('R.sortBy', () => {
it('passing type to sort function and list', () => {
const result = pipe(
[{ a: 2 }, { a: 1 }, { a: 0 }],
sortBy(x => {
return x.a
}),
)result[0].a // $ExpectType number
})
})
```[](#sortBy)
### sortObject
```typescript
sortObject(predicate: (aProp: string, bProp: string, aValue: T[K], bValue: T[K]) => number): (obj: T) => T
```It returns a sorted version of `input` object.
```javascript
const predicate = (propA, propB, valueA, valueB) => valueA > valueB ? -1 : 1const result = R.sortObject(predicate, {a:1, b: 4, c: 2})
// => {b: 4, c: 2, a: 1}
```Try this R.sortObject example in Rambda REPL
All TypeScript definitions
```typescript
sortObject(predicate: (aProp: string, bProp: string, aValue: T[K], bValue: T[K]) => number): (obj: T) => T;
sortObject(predicate: (aProp: string, bProp: string) => number): (obj: T) => T;
```R.sortObject source
```javascript
import { sort } from './sort.js'export function sortObject(predicate) {
return obj => {
const keys = Object.keys(obj)
const sortedKeys = sort((a, b) => predicate(a, b, obj[a], obj[b]))(keys)const toReturn = {}
sortedKeys.forEach(singleKey => {
toReturn[singleKey] = obj[singleKey]
})return toReturn
}
}
```Tests
```javascript
import { sortObject } from './sortObject.js'const obj = {
c: 7,
a: 100,
b: 1,
d: 4,
}test('happy', () => {
const predicate = (a, b, aValue, bValue) => {
if (a === 'a') {
return -1
}
if (b === 'a') {
return 1
}
return aValue > bValue ? -1 : 1
}
const result = sortObject(predicate)(obj)
const expected = {
a: 100,
c: 7,
d: 4,
b: 1,
}
expect(result).toEqual(expected)
})
```TypeScript test
```typescript
import { sortObject, pipe } from 'rambda'const obj = {
c: 1,
a: 2,
b: 3,
}describe('R.sortObject', () => {
it('predicate with all arguments', () => {
const result = pipe(
obj,
sortObject((propA, propB, valueA, valueB) => {
propA // $ExpectType string
propB // $ExpectType string
valueA // $ExpectType number
valueB // $ExpectType number
return propA > propB ? -1 : 1
}),
)result // $ExpectType { c: number; a: number; b: number; }
})it('predicate with only property arguments', () => {
const result = pipe(
obj,
sortObject((propA, propB) => {
propA // $ExpectType string
propB // $ExpectType string
return propA > propB ? -1 : 1
}),
)
result // $ExpectType { c: number; a: number; b: number; }
})
})
```[](#sortObject)
### sortWith
```javascript
const result = R.sortWith([
(a, b) => a.a === b.a ? 0 : a.a > b.a ? 1 : -1,
(a, b) => a.b === b.b ? 0 : a.b > b.b ? 1 : -1,
])([
{a: 1, b: 2},
{a: 2, b: 1},
{a: 2, b: 2},
{a: 1, b: 1},
])
const expected = [
{a: 1, b: 1},
{a: 1, b: 2},
{a: 2, b: 1},
{a: 2, b: 2},
]
// => `result` is equal to `expected`
```Try this R.sortWith example in Rambda REPL
[](#sortWith)
### split
```typescript
split(separator: string | RegExp): (str: string) => string[]
```All TypeScript definitions
```typescript
split(separator: string | RegExp): (str: string) => string[];
```R.split source
```javascript
export function split(separator) {
return str => str.split(separator)
}
```[](#split)
### splitEvery
```typescript
splitEvery(sliceLength: number): (input: T[]) => (T[])[]
```It splits `input` into slices of `sliceLength`.
```javascript
const result = [
R.splitEvery(2, [1, 2, 3]),
R.splitEvery(3, 'foobar')
]const expected = [
[[1, 2], [3]],
['foo', 'bar']
]
// => `result` is equal to `expected`
```Try this R.splitEvery example in Rambda REPL
All TypeScript definitions
```typescript
splitEvery(sliceLength: number): (input: T[]) => (T[])[];
```R.splitEvery source
```javascript
export function splitEvery(sliceLength) {
return list => {
if (sliceLength < 1) {
throw new Error('First argument to splitEvery must be a positive integer')
}const willReturn = []
let counter = 0while (counter < list.length) {
willReturn.push(list.slice(counter, (counter += sliceLength)))
}return willReturn
}
}
```Tests
```javascript
import { splitEvery } from './splitEvery.js'test('happy', () => {
expect(splitEvery(3)([1, 2, 3, 4, 5, 6, 7])).toEqual([[1, 2, 3], [4, 5, 6], [7]])
})
```TypeScript test
```typescript
import { pipe, splitEvery } from 'rambda'const list = [1, 2, 3, 4, 5, 6, 7]
describe('R.splitEvery', () => {
it('happy', () => {
const result = pipe(list, splitEvery(3))
result // $ExpectType number[][]
})
})
```[](#splitEvery)
### symmetricDifference
```typescript
symmetricDifference(x: T[]): (y: T[]) => T[]
```It returns a merged list of `x` and `y` with all equal elements removed.
`R.equals` is used to determine equality.
```javascript
const x = [ 1, 2, 3, 4 ]
const y = [ 3, 4, 5, 6 ]const result = R.symmetricDifference(x, y)
// => [ 1, 2, 5, 6 ]
```Try this R.symmetricDifference example in Rambda REPL
All TypeScript definitions
```typescript
symmetricDifference(x: T[]): (y: T[]) => T[];
```R.symmetricDifference source
```javascript
import { filter } from './filter.js'
import { includes } from './includes.js'export function symmetricDifference(x) {
return y => [
...filter(value => !includes(value)(y))(x),
...filter(value => !includes(value)(x))(y),
]
}
```Tests
```javascript
import { symmetricDifference } from './symmetricDifference.js'test('symmetricDifference', () => {
const list1 = [1, 2, 3, 4]
const list2 = [3, 4, 5, 6]
expect(symmetricDifference(list1)(list2)).toEqual([1, 2, 5, 6])
expect(symmetricDifference([])([])).toEqual([])
})test('symmetricDifference with objects', () => {
const list1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]
const list2 = [{ id: 3 }, { id: 4 }, { id: 5 }, { id: 6 }]
expect(symmetricDifference(list1)(list2)).toEqual([
{ id: 1 },
{ id: 2 },
{ id: 5 },
{ id: 6 },
])
})
```TypeScript test
```typescript
import { symmetricDifference } from 'rambda'describe('R.symmetricDifference', () => {
it('happy', () => {
const list1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]
const list2 = [{ id: 3 }, { id: 4 }, { id: 5 }, { id: 6 }]
const result = symmetricDifference(list1)(list2)result // $ExpectType { id: number; }[]
})
})
```[](#symmetricDifference)
### tail
```typescript
tail(input: T): T extends [any, ...infer U] ? U : [...T]
```It returns all but the first element of `input`.
```javascript
const result = [
R.tail([1, 2, 3]),
R.tail('foo')
]
// => [[2, 3], 'oo']
```Try this R.tail example in Rambda REPL
All TypeScript definitions
```typescript
tail(input: T): T extends [any, ...infer U] ? U : [...T];
tail(input: string): string;
```R.tail source
```javascript
import { drop } from './drop.js'export function tail(listOrString) {
return drop(1)(listOrString)
}
```Tests
```javascript
import { tail } from './tail.js'test('tail', () => {
expect(tail([1, 2, 3])).toEqual([2, 3])
expect(tail([1, 2])).toEqual([2])
expect(tail([1])).toEqual([])
expect(tail([])).toEqual([])expect(tail('abc')).toBe('bc')
expect(tail('ab')).toBe('b')
expect(tail('a')).toBe('')
expect(tail('')).toBe('')
})
```TypeScript test
```typescript
import { tail } from 'rambda'describe('R.tail', () => {
it('with string', () => {
const result = tail('foo')result // $ExpectType string
})
it('with list - one type', () => {
const result = tail([1, 2, 3])result // $ExpectType number[]
})
it('with list - mixed types', () => {
const result = tail(['foo', 'bar', 1, 2, 3])result // $ExpectType (string | number)[]
})
})
```[](#tail)
### take
```typescript
take(howMany: number): {
(input: string): string
```It returns the first `howMany` elements of `input`.
```javascript
const howMany = 2const result = [
R.take(howMany)([1, 2, 3]),
R.take(howMany, 'foobar'),
]
// => [[1, 2], 'fo']
```Try this R.take example in Rambda REPL
All TypeScript definitions
```typescript
take(howMany: number): {
(input: string): string;
(input: T[]): T[];
(input: readonly T[]): T[];
};
```R.take source
```javascript
import { baseSlice } from './_internals/baseSlice.js'export function take(numberOfItems) {
return input => {
if (numberOfItems < 0) {
return input.slice()
}
if (typeof input === 'string') {
return input.slice(0, numberOfItems)
}return baseSlice(input, 0, numberOfItems)
}
}
```Tests
```javascript
import { take } from './take.js'test('happy', () => {
const arr = ['foo', 'bar', 'baz']expect(take(1)(arr)).toEqual(['foo'])
expect(arr).toEqual(['foo', 'bar', 'baz'])
expect(take(2)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar'])
expect(take(3)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz'])
expect(take(4)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz'])
expect(take(3)('rambda')).toBe('ram')
})test('with negative index', () => {
expect(take(-1)([1, 2, 3])).toEqual([1, 2, 3])
expect(take(Number.NEGATIVE_INFINITY)([1, 2, 3])).toEqual([1, 2, 3])
})test('with zero index', () => {
expect(take(0)([1, 2, 3])).toEqual([])
})
```[](#take)
### takeLast
```typescript
takeLast(howMany: number): {
(input: string): string
```It returns the last `howMany` elements of `input`.
```javascript
const howMany = 2const result = [
R.takeLast(howMany)([1, 2, 3]),
R.takeLast(howMany)('foobar'),
]
// => [[2, 3], 'ar']
```Try this R.takeLast example in Rambda REPL
All TypeScript definitions
```typescript
takeLast(howMany: number): {
(input: string): string;
(input: T[]): T[];
(input: readonly T[]): T[];
};
```R.takeLast source
```javascript
import { baseSlice } from './_internals/baseSlice.js'export function takeLast(numberOfItems) {
return input => {
const len = input.length
if (numberOfItems < 0) {
return input.slice()
}
let numValue = numberOfItems > len ? len : numberOfItemsif (typeof input === 'string') {
return input.slice(len - numValue)
}numValue = len - numValue
return baseSlice(input, numValue, len)
}
}
```Tests
```javascript
import { takeLast } from './takeLast.js'test('with arrays', () => {
expect(takeLast(1)(['foo', 'bar', 'baz'])).toEqual(['baz'])
expect(takeLast(2)(['foo', 'bar', 'baz'])).toEqual(['bar', 'baz'])
expect(takeLast(3)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz'])
expect(takeLast(4)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz'])
expect(takeLast(10)(['foo', 'bar', 'baz'])).toEqual(['foo', 'bar', 'baz'])
})test('with strings', () => {
expect(takeLast(3)('rambda')).toBe('bda')
expect(takeLast(7)('rambda')).toBe('rambda')
})test('with negative index', () => {
expect(takeLast(-1)([1, 2, 3])).toEqual([1, 2, 3])
expect(takeLast(Number.NEGATIVE_INFINITY)([1, 2, 3])).toEqual([1, 2, 3])
})
```[](#takeLast)
### takeLastWhile
```typescript
takeLastWhile(predicate: (x: T) => boolean): (input: T[]) => T[]
``````javascript
const result = R.takeLastWhile(x => x > 2)([1, 2, 3, 4])
// => [3, 4]
```Try this R.takeLastWhile example in Rambda REPL
All TypeScript definitions
```typescript
takeLastWhile(predicate: (x: T) => boolean): (input: T[]) => T[];
takeLastWhile(predicate: (x: T, index: number) => boolean): (list: T[]) => T[];
```R.takeLastWhile source
```javascript
export function takeLastWhile(predicate) {
return input => {
if (input.length === 0) {
return input
}const toReturn = []
let counter = input.lengthwhile (counter) {
const item = input[--counter]
if (!predicate(item)) {
break
}
toReturn.push(item)
}return toReturn.reverse()
}
}
```Tests
```javascript
import { takeLastWhile } from './takeLastWhile.js'const list = [1, 2, 3, 4]
test('happy', () => {
const predicate = x => x > 2
const result = takeLastWhile(predicate)(list)
expect(result).toEqual([3, 4])
})test('predicate is always true', () => {
const predicate = () => true
const result = takeLastWhile(predicate)(list)
expect(result).toEqual(list)
})test('predicate is always false', () => {
const predicate = () => false
const result = takeLastWhile(predicate)(list)
expect(result).toEqual([])
})
```[](#takeLastWhile)
### takeWhile
```javascript
const list = [1, 2, 3, 4]
const predicate = x => x < 3const result = R.takeWhile(predicate)(list)
// => [1, 2]
```Try this R.takeWhile example in Rambda REPL
[](#takeWhile)
### tap
```typescript
tap(fn: (x: T) => void): (input: T) => T
```It applies function `fn` to input `x` and returns `x`.
One use case is debugging in the middle of `R.pipe` chain.
```javascript
const list = [1, 2, 3]R.pipe(
list,
R.map(x => x * 2)
R.tap(console.log),
R.filter(x => x > 1)
)
// => `2` and `3` will be logged
```Try this R.tap example in Rambda REPL
All TypeScript definitions
```typescript
tap(fn: (x: T) => void): (input: T) => T;
```R.tap source
```javascript
export function tap(fn) {
return x => {
fn(x)return x
}
}
```[](#tap)
### test
```typescript
test(regExpression: RegExp): (str: string) => boolean
```It determines whether `str` matches `regExpression`.
```javascript
R.test(/^f/)('foo')
// => true
```Try this R.test example in Rambda REPL
All TypeScript definitions
```typescript
test(regExpression: RegExp): (str: string) => boolean;
```R.test source
```javascript
export function test(pattern) {
return str => str.search(pattern) !== -1
}
```Tests
```javascript
import { test as testMethod } from './test.js'test('happy', () => {
expect(testMethod(/^x/)('xyz')).toBeTruthy()
expect(testMethod(/^y/)('xyz')).toBeFalsy()
})
```TypeScript test
```typescript
import { test } from 'rambda'const input = 'foo '
const regex = /foo/it('R.test', () => {
const result = test(regex)(input)result // $ExpectType boolean
})
```[](#test)
### tryCatch
It returns function that runs `fn` in `try/catch` block. If there was an error, then `fallback` is used to return the result.
```javascript
const fn = x => x.fooconst result = [
R.tryCatch(fn, false)(null),
R.tryCatch(fn, false)({foo: 'bar'})
]
// => [false, 'bar']
```Try this R.tryCatch example in Rambda REPL
[](#tryCatch)
### type
It accepts any input and it returns its type.
> :boom: `NaN`, `Promise` and `Async` are types specific for **Rambda**.
```javascript
const result = R.type(() => {}) // => 'Function'
R.type(async () => {}) // => 'Async'
R.type([]) // => 'Array'
R.type({}) // => 'Object'
R.type('foo') // => 'String'
R.type(1) // => 'Number'
R.type(true) // => 'Boolean'
R.type(null) // => 'Null'
R.type(/[A-z]/) // => 'RegExp'
R.type('foo'*1) // => 'NaN'const delay = ms => new Promise(resolve => {
setTimeout(function () {
resolve()
}, ms)
})
R.type(delay) // => 'Promise'
```Try this R.type example in Rambda REPL
[](#type)
### union
```typescript
union(x: T[]): (y: T[]) => T[]
```It takes two lists and return a new list containing a merger of both list with removed duplicates.
`R.equals` is used to compare for duplication.
```javascript
const result = R.union([1,2,3], [3,4,5]);
// => [1, 2, 3, 4, 5]
```Try this R.union example in Rambda REPL
All TypeScript definitions
```typescript
union(x: T[]): (y: T[]) => T[];
```R.union source
```javascript
import { cloneList } from './_internals/cloneList.js'
import { includes } from './includes.js'export function union(x) {
return y => {
const toReturn = cloneList(x)y.forEach(yInstance => {
if (!includes(yInstance)(x)) {
toReturn.push(yInstance)
}
})return toReturn
}
}
```Tests
```javascript
import { union } from './union.js'test('happy', () => {
expect(union([1, 2])([2, 3])).toEqual([1, 2, 3])
})test('with list of objects', () => {
const list1 = [{ a: 1 }, { a: 2 }]
const list2 = [{ a: 2 }, { a: 3 }]
const result = union(list1)(list2)
expect(result).toEqual([{ a: 1 }, { a: 2 }, { a: 3 }])
})
```TypeScript test
```typescript
import { union } from 'rambda'describe('R.union', () => {
it('happy', () => {
const result = union([1, 2])([2, 3])result // $ExpectType number[]
})
it('with array of objects - case 1', () => {
const list1 = [{ a: 1 }, { a: 2 }]
const list2 = [{ a: 2 }, { a: 3 }]
const result = union(list1)(list2)
result // $ExpectType { a: number; }[]
})
it('with array of objects - case 2', () => {
const list1 = [{ a: 1, b: 1 }, { a: 2 }]
const list2 = [{ a: 2 }, { a: 3, b: 3 }]
const result = union(list1)(list2)
result[0].a // $ExpectType number
result[0].b // $ExpectType number | undefined
})
})
```[](#union)
### uniq
```typescript
uniq(list: T[]): T[]
```It returns a new array containing only one copy of each element of `list`.
`R.equals` is used to determine equality.
```javascript
const list = [1, 1, {a: 1}, {a: 2}, {a:1}]R.uniq(list)
// => [1, {a: 1}, {a: 2}]
```Try this R.uniq example in Rambda REPL
All TypeScript definitions
```typescript
uniq(list: T[]): T[];
```R.uniq source
```javascript
import { _Set } from './_internals/set.js'export function uniq(list) {
const set = new _Set()
const willReturn = []
list.forEach(item => {
if (set.checkUniqueness(item)) {
willReturn.push(item)
}
})return willReturn
}
```Tests
```javascript
import { uniq } from './uniq.js'test('happy', () => {
const list = [1, 2, 3, 3, 3, 1, 2, 0]
expect(uniq(list)).toEqual([1, 2, 3, 0])
})test('with object', () => {
const list = [{ a: 1 }, { a: 2 }, { a: 1 }, { a: 2 }]
expect(uniq(list)).toEqual([{ a: 1 }, { a: 2 }])
})test('with nested array', () => {
expect(uniq([[42], [42]])).toEqual([[42]])
})test('with booleans', () => {
expect(uniq([[false], [false], [true]])).toEqual([[false], [true]])
})test('with falsy values', () => {
expect(uniq([undefined, null])).toEqual([undefined, null])
})test('can distinct between string and number', () => {
expect(uniq([1, '1'])).toEqual([1, '1'])
})
```TypeScript test
```typescript
import { uniq } from 'rambda'describe('R.uniq', () => {
it('happy', () => {
const result = uniq([1, 2, 3, 3, 3, 1, 2, 0])
result // $ExpectType number[]
})
})
```[](#uniq)
### uniqBy
It applies uniqueness to input list based on function that defines what to be used for comparison between elements.
`R.equals` is used to determine equality.
```javascript
const list = [{a:1}, {a:2}, {a:1}]
const result = R.uniqBy(x => x, list)// => [{a:1}, {a:2}]
```Try this R.uniqBy example in Rambda REPL
[](#uniqBy)
### uniqWith
```typescript
uniqWith(predicate: (x: T, y: T) => boolean): (list: T[]) => T[]
```It returns a new array containing only one copy of each element in `list` according to `predicate` function.
This predicate should return true, if two elements are equal.
```javascript
const list = [
{id: 0, title:'foo'},
{id: 1, title:'bar'},
{id: 2, title:'baz'},
{id: 3, title:'foo'},
{id: 4, title:'bar'},
]const expected = [
{id: 0, title:'foo'},
{id: 1, title:'bar'},
{id: 2, title:'baz'},
]const predicate = (x,y) => x.title === y.title
const result = R.uniqWith(predicate)(list)
// => `result` is equal to `expected`
```Try this R.uniqWith example in Rambda REPL
All TypeScript definitions
```typescript
uniqWith(predicate: (x: T, y: T) => boolean): (list: T[]) => T[];
```R.uniqWith source
```javascript
function includesWith(predicate, target, list) {
let willReturn = false
let index = -1while (++index < list.length && !willReturn) {
const value = list[index]if (predicate(target, value)) {
willReturn = true
}
}return willReturn
}export function uniqWith(predicate) {
return list => {
let index = -1
const willReturn = []while (++index < list.length) {
const value = list[index]if (!includesWith(predicate, value, willReturn)) {
willReturn.push(value)
}
}return willReturn
}
}
```Tests
```javascript
import { uniqWith } from './uniqWith.js'const list = [{ a: 1 }, { a: 1 }]
test('happy', () => {
const fn = (x, y) => x.a === y.aconst result = uniqWith(fn)(list)
expect(result).toEqual([{ a: 1 }])
})test('with list of strings', () => {
const fn = (x, y) => x.length === y.length
const list = ['0', '11', '222', '33', '4', '55']
const result = uniqWith(fn)(list)
expect(result).toEqual(['0', '11', '222'])
})test('should return items that are not equal to themselves', () => {
// test case based on https://github.com/remeda/remeda/issues/999
const data = [
{ id: 1, reason: 'No name' },
{ id: 1, reason: 'No name' },
{ reason: 'No name' },
{ reason: 'No name' },
]
const expectedResult = [
{ id: 1, reason: 'No name' },
{ reason: 'No name' },
{ reason: 'No name' },
]const result = uniqWith((errorA, errorB) => {
// the objects with no ids should effectively be ignored from removal of duplicates
if (errorA.id === undefined || errorB.id === undefined) {
return false
}
return errorA.id === errorB.id
})(data)expect(result).toEqual(expectedResult)
})
```TypeScript test
```typescript
import { pipe, uniqWith } from 'rambda'describe('R.uniqWith', () => {
it('happy', () => {
const result = pipe(
[{ a: 1 }, { a: 1 }],
uniqWith((x, y) => x.a === y.a),
)
result // $ExpectType { a: number; }[]
})
})
```[](#uniqWith)
### unless
```typescript
unless(predicate: (x: T) => boolean, whenFalseFn: (x: T) => U): (x: T) => T | U
```The method returns function that will be called with argument `input`.
If `predicate(input)` returns `false`, then the end result will be the outcome of `whenFalse(input)`.
In the other case, the final output will be the `input` itself.
```javascript
const fn = R.unless(
x => x > 2,
x => x + 10
)const result = [
fn(1),
fn(5)
]
// => [11, 5]
```Try this R.unless example in Rambda REPL
All TypeScript definitions
```typescript
unless(predicate: (x: T) => boolean, whenFalseFn: (x: T) => U): (x: T) => T | U;
unless(predicate: (x: T) => boolean, whenFalseFn: (x: T) => T): (x: T) => T;
```R.unless source
```javascript
export function unless(predicate, whenFalseFn) {
return input => {
if (predicate(input)) {
return input
}return whenFalseFn(input)
}
}
```Tests
```javascript
import { unless } from './unless.js'test('happy', () => {
expect(
unless(
x => x > 10,
x => x + 1,
)(20),
).toEqual(20)
expect(
unless(
x => x > 10,
x => x + 1,
)(5),
).toEqual(6)
})
```TypeScript test
```typescript
import { pipe, unless } from 'rambda'const inc = (x: number) => x + 1
describe('R.unless', () => {
it('happy', () => {
const result = pipe(
1,
unless(x => x > 5, inc),
)
result // $ExpectType number
})
it('with two different types', () => {
const result = pipe(
1,
unless(
x => {
x // $ExpectType number
return x > 5
},
x => {
x // $ExpectType number
return `${x}-foo`
},
),
)
result // $ExpectType string | number
})
})
```[](#unless)
### unwind
It takes an object and a property name. The method will return a list of objects, where each object is a shallow copy of the input object, but with the property array unwound.
```javascript
const obj = {
a: 1,
b: [2, 3],
}
const result = R.unwind('b')(obj)
const expected = [{a:1, b:2}, {a:1, b:3}]
// => `result` is equal to `expected`
```Try this R.unwind example in Rambda REPL
[](#unwind)
### update
```typescript
update(index: number, newValue: T): (list: T[]) => T[]
```It returns a copy of `list` with updated element at `index` with `newValue`.
```javascript
const index = 2
const newValue = 88
const list = [1, 2, 3, 4, 5]const result = R.update(index, newValue, list)
// => [1, 2, 88, 4, 5]
```Try this R.update example in Rambda REPL
All TypeScript definitions
```typescript
update(index: number, newValue: T): (list: T[]) => T[];
```R.update source
```javascript
import { cloneList } from './_internals/cloneList.js'export function update(index, newValue) {
return list => {
const clone = cloneList(list)
if (index === -1) {
return clone.fill(newValue, index)
}return clone.fill(newValue, index, index + 1)
}
}
```Tests
```javascript
import { update } from './update.js'const list = [1, 2, 3]
test('happy', () => {
const newValue = 8
const index = 1
const result = update(index, newValue)(list)const expected = [1, 8, 3]
expect(result).toEqual(expected)
})test('list has no such index', () => {
const newValue = 8
const index = 10
const result = update(index, newValue)(list)expect(result).toEqual(list)
})test('with negative index', () => {
expect(update(-1, 10)([1])).toEqual([10])
expect(update(-1, 10)([])).toEqual([])
expect(update(-1, 10)(list)).toEqual([1, 2, 10])
expect(update(-2, 10)(list)).toEqual([1, 10, 3])
expect(update(-3, 10)(list)).toEqual([10, 2, 3])
})
```[](#update)
### when
```typescript
when(predicate: (x: T) => boolean, whenTrueFn: (x: T) => T): (input: T) => T
```It pass `input` to `predicate` function and if the result is `true`, it will return the result of `whenTrueFn(input)`.
If the `predicate` returns `false`, then it will simply return `input`.```javascript
const predicate = x => typeof x === 'number'
const whenTrueFn = R.add(11)const fn = when(predicate, whenTrueResult)
const positiveInput = 88
const negativeInput = 'foo'const result = [
fn(positiveInput),
fn(positiveInput),
]const expected = [
99,
'foo',
]
// => `result` is equal to `expected`
```Try this R.when example in Rambda REPL
All TypeScript definitions
```typescript
when(predicate: (x: T) => boolean, whenTrueFn: (x: T) => T): (input: T) => T;
when(predicate: (x: T) => boolean, whenTrueFn: (x: T) => U): (input: T) => T | U;
```R.when source
```javascript
export function when(predicate, whenTrueFn) {
return input => {
if (!predicate(input)) {
return input
}return whenTrueFn(input)
}
}
```Tests
```javascript
import { when } from './when.js'const predicate = x => typeof x === 'number'
test('happy', () => {
const fn = when(predicate, x => x + 1)
expect(fn(11)).toBe(12)
expect(fn('foo')).toBe('foo')
})
```TypeScript test
```typescript
import { pipe, tap, when } from 'rambda'describe('R.when', () => {
it('happy', () => {
const result = pipe(
1,
when(
x => x > 2,
x => x,
),
tap(x => {
x // $ExpectType number
}),
when(
x => x > 2,
x => String(x),
),
)result // $ExpectType string | number
})
})
```[](#when)
### zip
```typescript
zip(x: K[]): (y: V[]) => KeyValuePair[]
```It will return a new array containing tuples of equally positions items from both `x` and `y` lists.
The returned list will be truncated to match the length of the shortest supplied list.
```javascript
const x = [1, 2]
const y = ['A', 'B']
R.zip(x)(y)
// => [[1, 'A'], [2, 'B']]// truncates to shortest list
R.zip([...x, 3])(['A', 'B'])
// => [[1, 'A'], [2, 'B']]
```Try this R.zip example in Rambda REPL
All TypeScript definitions
```typescript
zip(x: K[]): (y: V[]) => KeyValuePair[];
```R.zip source
```javascript
export function zip(left) {
return right => {
const result = []
const length = Math.min(left.length, right.length)for (let i = 0; i < length; i++) {
result[i] = [left[i], right[i]]
}return result
}
}
```Tests
```javascript
import { zip } from './zip.js'const array1 = [1, 2, 3]
const array2 = ['A', 'B', 'C']test('should return an array', () => {
const actual = zip(array1)(array2)
expect(actual).toBeInstanceOf(Array)
})test('should return and array or tuples', () => {
const expected = [
[1, 'A'],
[2, 'B'],
[3, 'C'],
]
const actual = zip(array1)(array2)
expect(actual).toEqual(expected)
})test('should truncate result to length of shorted input list', () => {
const expectedA = [
[1, 'A'],
[2, 'B'],
]
const actualA = zip([1, 2])(array2)
expect(actualA).toEqual(expectedA)const expectedB = [
[1, 'A'],
[2, 'B'],
]
const actualB = zip(array1)(['A', 'B'])
expect(actualB).toEqual(expectedB)
})
```TypeScript test
```typescript
import { zip } from 'rambda'describe('R.zip', () => {
it('happy', () => {
const array1 = [1, 2, 3]
const array2 = ['A', 'B', 'C']
let a: Partial
const result = zip(array1)(array2)
result[0][0] // $ExpectType number
result[0][1] // $ExpectType string
})
})
```[](#zip)
### zipWith
```typescript
zipWith(
fn: (x: T, y: U) => TResult,
list1: readonly T[],
): (list2: readonly U[]) => TResult[]
``````javascript
const list1 = [ 10, 20, 30, 40 ]
const list2 = [ 100, 200 ]const result = R.zipWith(R.add, list1)(list2)
// => [110, 220]
```Try this R.zipWith example in Rambda REPL
All TypeScript definitions
```typescript
zipWith(
fn: (x: T, y: U) => TResult,
list1: readonly T[],
): (list2: readonly U[]) => TResult[];
```R.zipWith source
```javascript
import { take } from './take.js'export function zipWith(fn, x) {
return y =>
take(x.length > y.length ? y.length : x.length)(x).map((xInstance, i) =>
fn(xInstance, y[i]),
)
}
```Tests
```javascript
import { zipWith } from './zipWith.js'const add = (x, y) => x + y
const list1 = [1, 2, 3]
const list2 = [10, 20, 30, 40]
const list3 = [100, 200]test('when second list is shorter', () => {
const result = zipWith(add, list1)(list3)
expect(result).toEqual([101, 202])
})test('when second list is longer', () => {
const result = zipWith(add, list1)(list2)
expect(result).toEqual([11, 22, 33])
})
```TypeScript test
```typescript
import { pipe, zipWith } from 'rambda'const list1 = [1, 2]
const list2 = [10, 20, 30]describe('R.zipWith', () => {
it('happy', () => {
const result = pipe(
list2,
zipWith((x, y) => {
x // $ExpectType number
y // $ExpectType number
return `${x}-${y}`
}, list1),
)result // $ExpectType string[]
})
})
```[](#zipWith)
## ❯ CHANGELOG
10.0.0
CHANGELOG - 10.0.0
This is major revamp of `Rambda` library:
- `R.pipe` is the recommended method for TypeScript chaining.
- All methods should be useful to work inside `R.pipe` chain. If method doesn't have clear use case inside `R.pipe`, it is removed as part of this revamp.
- There will be only one way to use each method. For example, `R.add` can be used only with `R.add(1)(2)`, i.e. it doesn't support `R.add(1, 2)`. This helps with testing and also with TypeScript definitions. This aligns with TypeScript focused approach of this library.
- Confusing methods are removed. For example, `R.cond` and `R.ifElse` are removed as their usage inside `R.piped` makes the whole chain less readable. Such logic should be part of your codebase, not part of external library.
- All methods that expect more than 1 input, will have to be called with `R.methodName(input1)(input2)` or `R.methodName(input1, input2)(input3)`. This is to make TypeScript definitions easier to maintain.
- Optimize many methods to better work in TypeScript context with `R.pipe`. The focus was passing objects through the `R.pipe` chain.
- Add `R.pipe` supports up to 20 functions, i.e. chain can be 20 functions long.
- `R.chain` is renamed to `R.flatMap`
- `R.comparator` is renamed to `R.sortingFn`- Remove following methods:
-- Lenses - `R.lens`, `R.lensProp`, `R.lensPath`, `R.view`, `R.set`, `R.over`
-- T, F
-- add
-- addIndex, addIndexRight
-- always
-- ap
-- applySpec
-- applyTo
-- assoc, assocPath, dissoc, dissocPath
-- binary
-- bind
-- call
-- collectBy
-- compose
-- composeWith
-- cond
-- converge
-- curry
-- difference, differenceWith
-- divide, multiply, subtract
-- endsWith/startsWith
-- flip
-- forEachObjIndexed
-- fromPairs
-- gte, lte, lt, gt
-- identical
-- ifElse
-- insert
-- juxt
-- length
-- mapObjIndexed
-- mergeAll, mergeLeft, mergeDeepLeft, mergeDeepRight
-- move
-- partitionIndexed
-- pickAll
-- pickBy
-- repeat
-- splitWhen
-- toLower/toUpper
-- unapply
-- unnest
-- update
-- without- Add following methods:
-- R.pipeAsync
-- R.addProp
-- R.createObjectFromKeys
-- R.mapAsync
-- R.mapParallelAsync
-- R.ascend/R.descend
-- R.shuffle
-- R.permutations
-- R.compact
-- R.rejectObject
-- R.findNth
-- R.combinations
-- R.rangeDescending- Rename following methods:
-- replaceItemAtIndex -> adjust
-- checkObjectWithSpec -> where
-- objectIncludes -> whereEq
-- modify -> modifyProp_ Regarding using object as input with TypeScript in methods such as `R.map/filter` - this feature is no longer supported in TypeScript as it has multiple issues when using inside pipes. In JS, it still works as before. Following methods are affected:
-- R.map
-- R.mapIndexed
-- R.filter
-- R.reject- Regarding using string as path input in `R.omit`, `R.pick` and `R.path` with TypeScript - now it require explicit definition of expected return type.
- Revert adding stopper logic in `R.reduce` - https://github.com/selfrefactor/rambda/pull/630
- Remove use of `Dictionary` custom interface and use more appropriate `Record`
- Remove use of `Record` in favour of `Record`
- Add TypeScript definition to handle common case of `R.filter(Boolean)` that will turn `Array` to `Array`.
- Regarding using object with `R.forEach` in TypeScript - this is no longer supported. Again, JS version still works with objects.
- head/last - empty array as input will return `undefined`, but `never`
- assocPath - stop supporting curring of type `(x)(y)(z)`- Stop support string inputs for some methods, since it was hard to correctly type them in TypeScript.
-- append/prepend
- Change `R.range` to work with `endIndex` included instead of `endIndex` excluded, i.e. `R.range(0, 2)` will return `[0, 1, 2]` instead of `[0, 1]`. This is done because `R.rangeDescending` is added and users would wonder if end or start index is excluded.
- Sync with typing of `@types/ramda`:
-- allPass
-- anyPass
-- append
-- both
-- countBy
-- drop
-- dropLast
-- dropRepeatsBy
-- either
-- filter
-- forEach
-- keys
-- map
-- mergeAll
-- modify
-- modifyPath
-- omit
-- partition
-- pluck
-- prepend
-- propEq
-- where
-- whereAny- Sync with typing of `remeda`:
-- filter
-- reject
-- map
-- mapObject
-- toPairs
-- partition- Publish to JSR registry - https://jsr.io/@rambda/rambda
- Replace Record with Record
- Improve TypeScript definitions of:
-- objOf
-- pluck
-- mergeWith- Change `Jest` with `Vitest`.
- Remove `Babel` dependency in `Rollup` build setup.
- Revert adding stopper logic in `R.reduce` - https://github.com/selfrefactor/rambda/pull/630
- Renamed methods:
-- `chain` to `flatMap`
-- `mapObjIndexed` to `mapObject`9.4.2
- Fix TS issue when `R.take` is used as part of `R.pipe`.
Moving away from `Ramda` types which are problematic in this case:
```typescript
const data = ['foo', 'bar', 'baz', 'qux']
const result = piped(
data,
filter(
x => x.length >= 2
),
takeLast(2),
)
```9.4.1
- Fix bug with `R.differenceWith` when two arrays has same length - [Issue #750](https://github.com/selfrefactor/rambda/issues/757)
- Allow path input to not be transformed when string numbers are there - [Issue #750](https://github.com/selfrefactor/rambda/issues/750)
9.4.0
- Fix `deno` release
- Fix too strict `true` condition in `R.ifElse` - [Issue #750](https://github.com/selfrefactor/rambda/issues/750)
- Change `R.groupBy` typings to match `@types/ramda` typings
9.3.0
- Breaking change in relation to TS typings of `R.assoc`, `R.dissoc` and `R.modify` - https://github.com/ramda/types/pull/37
- Add `R.isNotEmpty` as it is new method in `Ramda`
- Fix `R.head`/`R.last` TS definition - It returns `undefined` if array has length of 0. Before
9.2.1
- Broken `Deno` build - [Issue #731](https://github.com/selfrefactor/rambda/issues/731)
9.2.0
- `R.once` TS type definition miss to context argument and its type - [Issue #728](https://github.com/selfrefactor/rambda/issues/728)
- Fix implementation of `R.unless` function - https://github.com/selfrefactor/rambda/pull/726
9.1.1
- Faster R.equals with Object.is short circuit - https://github.com/selfrefactor/rambda/pull/725
- Fix R.cond transform is unary - https://github.com/selfrefactor/rambda/issues/720
9.1.0
Add these methods
- insert
- insertAll
- lt
- lte
- isNotNil
- pickBy
- pathSatisfies
- swap
- mergeDeepLeft9.0.1
- Fix bad TS typings, due to missing declaration - [Issue #716](https://github.com/selfrefactor/rambda/issues/716)
9.0.0
Breaking change in TS definitions of `lenses` as now they are synced to `Ramda` types.
- Add `R.sortWith` - [Issue #707](https://github.com/selfrefactor/rambda/issues/707)
- Add `R.innerJoin`, `R.gt`, `R.gte`, `R.reduceBy`, `R.hasIn`
8.6.0
- Wrong typing for `R.dissocPath` - [Issue #709](https://github.com/selfrefactor/rambda/issues/709)
- Update build dependencies
8.5.0
- Revert changes in `R.anyPass` introduced in `8.4.0` release. The reason is that the change was breaking the library older than `5.2.0` TypeScript.
- Wrong `R.partial` TS definition - [Issue #705](https://github.com/selfrefactor/rambda/issues/705)
- Add `R.dropRepeatsBy`
- Add `R.empty`
- Add `R.eqBy`
- Add `R.forEachObjIndexed`
8.4.0
- Add `R.dissocPath`
- Fix TS definitions of `R.head/R.last` and add missing handle of empty string
- Add `R.removeIndex` - method was before only in `Rambdax`, but now since `R.dissocPath` is using it, it is added to main library.
- Allow `R.omit` to pass numbers as part of properties to omit, i.e. `R.omit(['a', 1], {a: {1: 1, 2: 2}})`
- R.keys always returns strings - [MR #700](https://github.com/selfrefactor/rambda/pull/700)
- Improve `R.prepend/R.append` type interference - [MR #699](https://github.com/selfrefactor/rambda/pull/699)
- Change `R.reduce` TS definitions so index is always received - [MR #696](https://github.com/selfrefactor/rambda/pull/696)
- Functions as a type guard in `R.anyPass` TS definitions - [MR #695](https://github.com/selfrefactor/rambda/pull/695)
- Fix R.append's curried type - [MR #694](https://github.com/selfrefactor/rambda/pull/694)
- Fix cannot compare errors in `Deno` with `R.equals` - [Issue #704](https://github.com/selfrefactor/rambda/issues/704).
- Fix cannot compare `BigInt` with `R.equals`
8.3.0
Add the following methods:
- binary
- call
- collectBy
- comparator
- composeWith8.2.0
Add the following methods:
- addIndex
- addIndexRight
- ap
- aperture
- applyTo
- ascend
- descend8.1.0
- Fix input order of TS definitions for `R.propEq` method - [Issue #688](https://github.com/selfrefactor/rambda/issues/688). The issue was due to 8.0.0 was shipped with TS definitions of `7.5.0` release.
- Add `R.differenceWith` method - [Issue #91](https://github.com/selfrefactor/rambdax/issues/91)
8.0.0
- handle falsy values in merge methods - https://github.com/ramda/ramda/pull/3222
- `R.head`/`R.last` don't return `undefined` for non-empty arrays
- `R.type` supports dates in TS definition - `Rambda` already did support dates in JS.
- Improve typings of `R.endsWith/startsWith` with regard to `string` input. - [PR #622](https://github.com/selfrefactor/rambda/pull/622)
- Handle list as falsy value in `R.reduce` - [Ramda MR](https://github.com/ramda/ramda/pull/2997/files)
- `R.nop` is removed - it will be moved to `Rambdax` as `R.noop`
- `R.includes` is no longer using string literal in TypeScript definitions
> Reason for breaking change - synchronize with Ramda `0.29.0` release:
- change order of `R.propEq` - [Ramda MR](https://github.com/ramda/ramda/pull/2938/files)
7.5.0
- IMPORTANT: Remove `export` property in `package.json` in order to allow `Rambda` support for projects with `"type": "module"` in `package.json` - [Issue #667](https://github.com/selfrefactor/rambda/issues/657)
- Add `R.unnest` - [Rambdax issue 89](https://github.com/selfrefactor/rambdax/issues/89)
- `R.uniq` is not using `R.equals` as Ramda does - [Issue #88](https://github.com/selfrefactor/rambdax/issues/88)
- Fix `R.path(['non','existing','path'], obj)` TS definition as 7.4.0 release caused TS errors - [Issue #668](https://github.com/selfrefactor/rambda/issues/668)
7.4.0
- Synchronize with `@types/ramda` - `R.prop`, `R.path`, `R.pickAll`
- Remove `esm` Rollup output due to tree-shaking issues.
- Upgrade all dev dependencies.
7.3.0
- Important - changing import declaration in `package.json` in order to fix tree-shaking issue - [Issue #647](https://github.com/selfrefactor/rambda/issues/647)
- Add `R.modify`
- Allow multiple inputs in TypeScript versions of `R.anyPass` and `R.allPass` - [Issue #642](https://github.com/selfrefactor/rambda/issues/604)
- Using wrong clone of object in `R.mergeDeepRight` - [Issue #650](https://github.com/selfrefactor/rambda/issues/650)
- Missing early return in `R.where` - [Issue #648](https://github.com/selfrefactor/rambda/issues/648)
- `R.allPass` doesn't accept more than 1 parameters for function predicates- [Issue #604](https://github.com/selfrefactor/rambda/issues/604)
7.2.1
- Remove bad typings of `R.propIs` which caused the library to cannot be build with TypeScript.
- Drop support for `Wallaby` as per [https://github.com/wallabyjs/public/issues/3037](https://github.com/wallabyjs/public/issues/3037)
7.2.0
- Wrong `R.update` if index is `-1` - [PR #593](https://github.com/selfrefactor/rambda/pull/593)
- Wrong curried typings in `R.anyPass` - [Issue #642](https://github.com/selfrefactor/rambda/issues/642)
- `R.modifyPath` not exported - [Issue #640](https://github.com/selfrefactor/rambda/issues/640)
- Add new method `R.uniqBy`. Implementation is coming from [Ramda MR#2641](https://github.com/ramda/ramda/pull/2641)
- Apply the following changes from `@types/rambda`:
-- [https://github.com/DefinitelyTyped/DefinitelyTyped/commit/bab47272d52fc7bb81e85da36dbe9c905a04d067](add `AnyFunction` and `AnyConstructor`)
-- Improve `R.ifElse` typings - https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59291
-- Make `R.propEq` safe for `null/undefined` arguments - https://github.com/ramda/ramda/pull/2594/files
7.1.4
- `R.mergeRight` not found on `Deno` import - [Issue #633](https://github.com/selfrefactor/rambda/issues/633)
7.1.0
- Add `R.mergeRight` - introduced by Ramda's latest release. While Ramda renames `R.merge`, Rambda will keep `R.merge`.
- Rambda's `pipe/compose` doesn't return proper length of composed function which leads to issue with `R.applySpec`. It was fixed by using Ramda's `pipe/compose` logic - [Issue #627](https://github.com/selfrefactor/rambda/issues/627)
- Replace `Async` with `Promise` as return type of `R.type`.
- Add new types as TypeScript output for `R.type` - "Map", "WeakMap", "Generator", "GeneratorFunction", "BigInt", "ArrayBuffer"
- Add `R.juxt` method
- Add `R.propSatisfies` method
- Add new methods after `Ramda` version upgrade to `0.28.0`:
-- R.count
-- R.modifyPath
-- R.on
-- R.whereAny
-- R.partialObject7.0.3
Rambda.none has wrong logic introduced in version `7.0.0` - [Issue #625](https://github.com/selfrefactor/rambda/issues/625)
7.0.2
Rambda doesn't work with `pnpm` due to wrong export configuration - [Issue #619](https://github.com/selfrefactor/rambda/issues/619)
7.0.1
- Wrong ESM export configuration in `package.json` - [Issue #614](https://github.com/selfrefactor/rambda/issues/614)
7.0.0
- Breaking change - sync `R.compose`/`R.pipe` with `@types/ramda`. That is significant change so as safeguard, it will lead a major bump. Important - this lead to raising required TypeScript version to `4.2.2`. In other words, to use `Rambda` you'll need TypeScript version `4.2.2` or newer.
Related commit in `@types/ramda` - https://github.com/DefinitelyTyped/DefinitelyTyped/commit/286eff4f76d41eb8f091e7437eabd8a60d97fc1f#diff-4f74803fa83a81e47cb17a7d8a4e46a7e451f4d9e5ce2f1bd7a70a72d91f4bc1
There are several other changes in `@types/ramda` as stated in [this comment](https://github.com/ramda/ramda/issues/2976#issuecomment-990408945). This leads to change of typings for the following methods in **Rambda**:
-- R.unless
-- R.toString
-- R.ifElse
-- R.always
-- R.complement
-- R.cond
-- R.is
-- R.sortBy
-- R.dissoc
-- R.toPairs
-- R.assoc
-- R.toLower
-- R.toUpper
- One more reason for the breaking change is changing of export declarations in `package.json` based on [this blog post](https://devblogs.microsoft.com/typescript/announcing-typescript-4-5-beta/#packagejson-exports-imports-and-self-referencing) and [this merged Ramda's PR](https://github.com/ramda/ramda/pull/2999). This also led to renaming of `babel.config.js` to `babel.config.cjs`.
- Add `R.apply`, `R.bind` and `R.unapply`
- `R.startsWith/R.endsWith` now support lists as inputs. This way, it matches current Ramda behavior.
- Remove unused typing for `R.chain`.
- `R.map`/`R.filter` no longer accept bad inputs as iterable. This way, Rambda behaves more like Ramda, which also throws.
- Make `R.lastIndexOf` follow the logic of `R.indexOf`.
- Change `R.type` logic to Ramda logic. This way, `R.type` can return `Error` and `Set` as results.
- Add missing logic in `R.equals` to compare sets - [Issue #599](https://github.com/selfrefactor/rambda/issues/599)
- Improve list cloning - [Issue #595](https://github.com/selfrefactor/rambda/issues/595)
- Handle multiple inputs with `R.allPass` and `R.anyPass` - [Issue #604](https://github.com/selfrefactor/rambda/issues/604)
- Fix `R.length` wrong logic with inputs as `{length: 123}` - [Issue #606](https://github.com/selfrefactor/rambda/issues/606).
- Improve non-curry typings of `R.merge` by using types from [mobily/ts-belt](https://github.com/mobily/ts-belt).
- Improve performance of `R.uniqWith`.
- Wrong `R.update` if index is `-1` - [PR #593](https://github.com/selfrefactor/rambda/pull/593)
- Make `R.eqProps` safe for falsy inputs - based on [this opened Ramda PR](https://github.com/ramda/ramda/pull/2943).
- Incorrect benchmarks for `R.pipe/R.compose` - [Issue #608](https://github.com/selfrefactor/rambda/issues/608)
- Fix `R.last/R.head` typings - [Issue #609](https://github.com/selfrefactor/rambda/issues/609)
6.9.0
- Fix slow `R.uniq` methods - [Issue #581](https://github.com/selfrefactor/rambda/issues/581)
Fixing `R.uniq` was done by improving `R.indexOf` which has performance implication to all methods importing `R.indexOf`:
- R.includes
- R.intersection
- R.difference
- R.excludes
- R.symmetricDifference
- R.union- R.without no longer support the following case - `without('0:1', ['0', '0:1']) // => ['0']`. Now it throws as the first argument should be a list, not a string. Ramda, on the other hand, returns an empty list - https://github.com/ramda/ramda/issues/3086.
6.8.3
- Fix TypeScript build process with `rambda/immutable` - [Issue #572](https://github.com/selfrefactor/rambda/issues/572)
- Add `R.objOf` method
- Add `R.mapObjIndexed` method
- Publish shorter README.md version to NPM
6.8.0
- `R.has` use `Object.prototype.hasOwnProperty`- [Issue #572](https://github.com/selfrefactor/rambda/issues/572)
- Expose `immutable.ts` typings which are Rambda typings with `readonly` statements - [Issue #565](https://github.com/selfrefactor/rambda/issues/565)
- Fix `R.intersection` wrong order compared to Ramda.
- `R.path` wrong return of `null` instead of `undefined` when path value is `null` - [PR #577](https://github.com/selfrefactor/rambda/pull/577)
6.7.0
- Remove `ts-toolbelt` types from TypeScript definitions. Most affected are the following methods, which lose one of its curried definitions:
1. R.maxBy
2. R.minBy
3. R.pathEq
4. R.viewOr
5. R.when
6. R.merge
7. R.mergeDeepRight
8. R.mergeLeft6.6.0
- Change `R.piped` typings to mimic that of `R.pipe`. Main difference is that `R.pipe` is focused on unary functions.
- Fix wrong logic when `R.without` use `R.includes` while it should use array version of `R.includes`.
- Use uglify plugin for UMD bundle.
- Remove `dist` folder from `.gitignore` in order to fix `Deno` broken package. [Issue #570](https://github.com/selfrefactor/rambda/issues/570)
- Improve `R.fromPairs` typings - [Issue #567](https://github.com/selfrefactor/rambda/issues/567)
6.5.3
- Wrong logic where `R.without` use `R.includes` while it should use the array version of `R.includes`
This is Ramda bug, that Rambda also has before this release - https://github.com/ramda/ramda/issues/3086
6.5.2
- Wrong `R.defaultTo` typings - changes introduced in v6.5.0 are missing their TS equivalent.
- Update dependencies
6.5.1
Fix wrong versions in changelog
6.5.0
- `R.defaultTo` no longer accepts infinite inputs, thus it follows Ramda implementation.
- `R.equals` supports equality of functions.
- `R.pipe` doesn't use `R.compose`.
- Close [Issue #561](https://github.com/selfrefactor/rambda/issues/561) - export several internal TS interfaces and types
- Close [Issue #559](https://github.com/selfrefactor/rambda/issues/559) - improve `R.propOr` typings
- Add `CHANGELOG.md` file in release files list
> This is only part of the changelog. You can read the full text in [CHANGELOG.md](CHANGELOG.md) file.
[](#-changelog)
## ❯ Additional info
> Most influential contributors(in alphabetical order)
-  [@farwayer](https://github.com/farwayer) - improving performance in R.find, R.filter; give the idea how to make benchmarks more reliable;
-  [@thejohnfreeman](https://github.com/thejohnfreeman) - add R.assoc, R.chain;
-  [@peeja](https://github.com/peeja) - add several methods and fix mutiple issues; provides great MR documentation
-  [@helmuthdu](https://github.com/helmuthdu) - add R.clone; help improve code style;
-  [@jpgorman](https://github.com/jpgorman) - add R.zip, R.reject, R.without, R.addIndex;
-  [@ku8ar](https://github.com/ku8ar) - add R.slice, R.propOr, R.identical, R.propIs and several math related methods; introduce the idea to display missing Ramda methods;
-  [@romgrk](https://github.com/romgrk) - add R.groupBy, R.indexBy, R.findLast, R.findLastIndex;
-  [@squidfunk](https://github.com/squidfunk) - add R.assocPath, R.symmetricDifference, R.difference, R.intersperse;
-  [@synthet1c](https://github.com/synthet1c) - add all lenses methods; add R.applySpec, R.converge;
-  [@vlad-zhukov](https://github.com/vlad-zhukov) - help with configuring Rollup, Babel; change export file to use ES module exports;
> Rambda references
- [Interview with Dejan Totef at SurviveJS blog](https://survivejs.com/blog/rambda-interview/)
- [Awesome functional Javascript programming libraries](https://github.com/stoeffel/awesome-fp-js#libraries)
- [Overview of Rambda pros/cons](https://mobily.github.io/ts-belt/docs/#rambda-%EF%B8%8F)
> Links to Rambda
- [awesome-fp-js](https://github.com/stoeffel/awesome-fp-js)
- [Web Tools Weekly #280](https://mailchi.mp/webtoolsweekly/web-tools-280)
- [awesome-docsify](https://github.com/docsifyjs/awesome-docsify)
> Deprecated from `Used by` section
- [SAP's Cloud SDK](https://github.com/SAP/cloud-sdk) - This repo doesn't uses `Rambda` since *October/2020* [commit that removes Rambda](https://github.com/SAP/cloud-sdk/commit/b29b4f915c4e4e9c2441e7b6b67cf83dac1fdac3)
[](#-additional-info)
## My other libraries
Niketa theme
Collection of 9 light VSCode themes
Niketa dark theme
Collection of 9 dark VSCode themes
String-fn
String utility library
Useful Javascript libraries
Large collection of JavaScript,TypeScript and Angular related repos links
Run-fn
CLI commands for lint JS/TS files, commit git changes and upgrade of dependencies
## Stargazers over time
[](https://starchart.cc/selfrefactor/rambda)