rambdax
                                
                                 rambdax copied to clipboard
                                
                                    rambdax copied to clipboard
                            
                            
                            
                        Extended version of Rambda
Rambdax
Extended version of Rambda(utility library) - Documentation
Rambda is smaller and faster  alternative to the popular functional programming library Ramda. - Documentation
❯ Differences between Rambda and Rambdax
Rambdax passthrough all Rambda methods and introduce some new functions.
The idea of Rambdax is to extend Rambda without worring for Ramda compatibility.

❯ Example use
import { composeAsync, filter, delay, mapAsync } from 'rambdax'
const result = await composeAsync(
  mapAsync(async x => {
    await delay(100)
    return x + 1
  }),
  filter(x => x > 1)
)([1, 2, 3])
// => [3, 4]
You can test this example in Rambda's REPL
- Differences between Rambda and Ramda
- API
- Changelog

❯ Rambdax's advantages
Typescript included
Typescript definitions are included in the library, in comparison to Ramda, where you need to additionally install @types/ramda.
Still, you need to be aware that functional programming features in Typescript are in development, which means that using R.compose/R.pipe can be problematic.
Important - Rambdax version 9.0.0(or higher) requires Typescript version 4.3.3(or higher).
Dot notation for R.path, R.paths, R.assocPath and R.lensPath
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} })
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
Extendable with Ramda community projects
Rambdax implements some methods from Ramda community projects, such as R.lensSatisfies, R.lensEq and R.viewOr.
Alternative TS definitions
Alternative TS definitions are available as rambdax/immutable. These are Rambdax definitions linted with ESLint functional/prefer-readonly-type plugin.

❯ Missing Ramda methods
Click to see the full list of 78 Ramda methods not implemented in Rambda
- __
- addIndex
- ap
- aperture
- applyTo
- ascend
- binary
- call
- collectBy
- comparator
- composeWith
- construct
- constructN
- descend
- differenceWith
- dissocPath
- empty
- eqBy
- forEachObjIndexed
- gt
- gte
- hasIn
- innerJoin
- insert
- insertAll
- into
- invert
- invertObj
- invoker
- keysIn
- lift
- liftN
- lt
- lte
- mapAccum
- mapAccumRight
- memoizeWith
- mergeDeepLeft
- mergeDeepWith
- mergeDeepWithKey
- mergeWithKey
- modify
- nAry
- nthArg
- o
- otherwise
- pair
- partialRight
- pathSatisfies
- pickBy
- pipeWith
- project
- promap
- reduceBy
- reduceRight
- reduceWhile
- reduced
- remove
- scan
- sequence
- sortWith
- splitWhenever
- symmetricDifferenceWith
- andThen
- toPairsIn
- transduce
- traverse
- unary
- uncurryN
- unfold
- unionWith
- unnest
- until
- useWith
- valuesIn
- xprod
- thunkify
- default

❯ Install
- 
yarn add rambdax 
- 
For UMD usage either use ./dist/rambdax.umd.jsor the following CDN link:
https://unpkg.com/rambdax@CURRENT_VERSION/dist/rambdax.umd.js
- with deno
import {compose, add} from 'https://raw.githubusercontent.com/selfrefactor/rambdax/master/dist/rambdax.esm.js'

Differences between Rambda and Ramda
- 
Rambda's type detects async functions and unresolved Promises. The returned values are'Async'and'Promise'.
- 
Rambda's type handles NaN input, in which case it returns NaN.
- 
Rambda's forEach can iterate over objects not only arrays. 
- 
Rambda's map, filter, partition when they iterate over objects, they pass property and input object as predicate's argument. 
- 
Rambda's filter returns empty array with bad input( nullorundefined), while Ramda throws.
- 
Ramda's clamp work with strings, while Rambda's method work only with numbers. 
- 
Ramda's indexOf/lastIndexOf work with strings and lists, while Rambda's method work only with lists as iterable input. 
- 
Error handling, when wrong inputs are provided, may not be the same. This difference will be better documented once all brute force tests are completed. 
- 
Typescript definitions between rambdaand@types/ramdamay vary.

❯ Benchmarks
Click to expand all benchmark results
There are methods which are benchmarked only with Ramda and Rambda(i.e. no Lodash).
Note that some of these methods, are called with and without curring. This is done in order to give more detailed performance feedback.
The benchmarks results are produced from latest versions of Rambda, Lodash(4.17.21) and Ramda(0.28.0).
Ramda and Rambda(i.e. no Lodash).| method | Rambda | Ramda | Lodash | 
|---|---|---|---|
| add | 🚀 Fastest | 21.52% slower | 82.15% slower | 
| adjust | 8.48% slower | 🚀 Fastest | 🔳 | 
| all | 🚀 Fastest | 1.81% slower | 🔳 | 
| allPass | 🚀 Fastest | 91.09% slower | 🔳 | 
| allPass | 🚀 Fastest | 98.56% slower | 🔳 | 
| and | 🚀 Fastest | 89.09% slower | 🔳 | 
| any | 🚀 Fastest | 92.87% slower | 45.82% slower | 
| anyPass | 🚀 Fastest | 98.25% slower | 🔳 | 
| append | 🚀 Fastest | 2.07% slower | 🔳 | 
| applySpec | 🚀 Fastest | 80.43% slower | 🔳 | 
| assoc | 72.32% slower | 60.08% slower | 🚀 Fastest | 
| clone | 🚀 Fastest | 91.86% slower | 86.48% slower | 
| compose | 🚀 Fastest | 32.45% slower | 13.68% slower | 
| converge | 78.63% slower | 🚀 Fastest | 🔳 | 
| curry | 🚀 Fastest | 28.86% slower | 🔳 | 
| curryN | 🚀 Fastest | 41.05% slower | 🔳 | 
| defaultTo | 🚀 Fastest | 48.91% slower | 🔳 | 
| drop | 🚀 Fastest | 82.35% slower | 🔳 | 
| dropLast | 🚀 Fastest | 86.74% slower | 🔳 | 
| equals | 58.37% slower | 96.73% slower | 🚀 Fastest | 
| filter | 6.7% slower | 72.03% slower | 🚀 Fastest | 
| find | 🚀 Fastest | 85.14% slower | 42.65% slower | 
| findIndex | 🚀 Fastest | 86.48% slower | 72.27% slower | 
| flatten | 🚀 Fastest | 95.26% slower | 10.27% slower | 
| ifElse | 🚀 Fastest | 58.56% slower | 🔳 | 
| includes | 🚀 Fastest | 84.63% slower | 🔳 | 
| indexOf | 🚀 Fastest | 76.63% slower | 🔳 | 
| indexOf | 🚀 Fastest | 82.2% slower | 🔳 | 
| init | 🚀 Fastest | 92.24% slower | 13.3% slower | 
| is | 🚀 Fastest | 57.69% slower | 🔳 | 
| isEmpty | 🚀 Fastest | 97.14% slower | 54.99% slower | 
| last | 🚀 Fastest | 93.43% slower | 5.28% slower | 
| lastIndexOf | 🚀 Fastest | 85.19% slower | 🔳 | 
| map | 🚀 Fastest | 86.6% slower | 11.73% slower | 
| match | 🚀 Fastest | 44.83% slower | 🔳 | 
| merge | 🚀 Fastest | 12.21% slower | 55.76% slower | 
| none | 🚀 Fastest | 96.48% slower | 🔳 | 
| objOf | 🚀 Fastest | 38.05% slower | 🔳 | 
| omit | 🚀 Fastest | 69.95% slower | 97.34% slower | 
| over | 🚀 Fastest | 56.23% slower | 🔳 | 
| path | 37.81% slower | 77.81% slower | 🚀 Fastest | 
| pick | 🚀 Fastest | 19.07% slower | 80.2% slower | 
| pipe | 0.87% slower | 🚀 Fastest | 🔳 | 
| prop | 🚀 Fastest | 87.95% slower | 🔳 | 
| propEq | 🚀 Fastest | 91.92% slower | 🔳 | 
| range | 🚀 Fastest | 61.8% slower | 57.44% slower | 
| reduce | 60.48% slower | 77.1% slower | 🚀 Fastest | 
| repeat | 48.57% slower | 68.98% slower | 🚀 Fastest | 
| replace | 33.45% slower | 33.99% slower | 🚀 Fastest | 
| set | 🚀 Fastest | 50.35% slower | 🔳 | 
| sort | 🚀 Fastest | 40.23% slower | 🔳 | 
| sortBy | 🚀 Fastest | 25.29% slower | 56.88% slower | 
| split | 🚀 Fastest | 55.37% slower | 17.64% slower | 
| splitEvery | 🚀 Fastest | 71.98% slower | 🔳 | 
| take | 🚀 Fastest | 91.96% slower | 4.72% slower | 
| takeLast | 🚀 Fastest | 93.39% slower | 19.22% slower | 
| test | 🚀 Fastest | 82.34% slower | 🔳 | 
| type | 🚀 Fastest | 48.6% slower | 🔳 | 
| uniq | 🚀 Fastest | 90.24% slower | 🔳 | 
| uniqWith | 18.09% slower | 🚀 Fastest | 🔳 | 
| uniqWith | 14.23% slower | 🚀 Fastest | 🔳 | 
| update | 🚀 Fastest | 52.35% slower | 🔳 | 
| view | 🚀 Fastest | 76.15% slower | 🔳 | 

❯ Used by
- 
Walmart Canada reported by w-b-dev 

API
add
add(a: number, b: number): number
It adds a and b.
:boom: It doesn't work with strings, as the inputs are parsed to numbers before calculation.
R.add(2, 3) // =>  5
Try this R.add example in Rambda REPL
R.add source
export function add(a, b){
  if (arguments.length === 1) return _b => add(a, _b)
  return Number(a) + Number(b)
}

adjust
adjust<T>(index: number, replaceFn: (x: T) => T, list: T[]): T[]
It replaces index in array list with the result of replaceFn(list[i]).
R.adjust(
  0,
  a => a + 1,
  [0, 100]
) // => [1, 100]
Try this R.adjust example in Rambda REPL
R.adjust source
import { cloneList } from './_internals/cloneList.js'
import { curry } from './curry.js'
function adjustFn(
  index, replaceFn, 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
}
export const adjust = curry(adjustFn)

all
all<T>(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.
const list = [ 0, 1, 2, 3, 4 ]
const predicate = x => x > -1
const result = R.all(predicate, list)
// => true
Try this R.all example in Rambda REPL
R.all source
export function all(predicate, list){
  if (arguments.length === 1) return _list => all(predicate, _list)
  for (let i = 0; i < list.length; i++){
    if (!predicate(list[ i ])) return false
  }
  return true
}

allFalse
allFalse(...inputs: any[]): boolean
It returns true if all inputs arguments are falsy(empty objects and empty arrays are considered falsy).
Functions are valid inputs, but these functions cannot have their own arguments.
This method is very similar to R.anyFalse, R.anyTrue and R.allTrue
R.allFalse(0, null, [], {}, '', () => false)
// => true
Try this R.allFalse example in Rambda REPL
R.allFalse source
import { isTruthy } from './_internals/isTruthy.js'
import { type } from './type.js'
export function allFalse(...inputs){
  let counter = 0
  while (counter < inputs.length){
    const x = inputs[ counter ]
    if (type(x) === 'Function'){
      if (isTruthy(x())){
        return false
      }
    } else if (isTruthy(x)){
      return false
    }
    counter++
  }
  return true
}

allPass
allPass<T>(predicates: ((x: T) => boolean)[]): (input: T) => boolean
It returns true, if all functions of predicates return true, when input is their argument.
const input = {
  a : 1,
  b : 2,
}
const predicates = [
  x => x.a === 1,
  x => x.b === 2,
]
const result = R.allPass(predicates)(input) // => true
Try this R.allPass example in Rambda REPL
R.allPass source
export function allPass(predicates){
  return (...input) => {
    let counter = 0
    while (counter < predicates.length){
      if (!predicates[ counter ](...input)){
        return false
      }
      counter++
    }
    return true
  }
}

allTrue
allTrue(...input: any[]): boolean
It returns true if all inputs arguments are truthy(empty objects and empty arrays are considered falsy).
R.allTrue(1, true, {a: 1}, [1], 'foo', () => true)
// => true
Try this R.allTrue example in Rambda REPL
R.allTrue source
import { isFalsy } from './_internals/isFalsy.js'
import { type } from './type.js'
export function allTrue(...inputs){
  let counter = 0
  while (counter < inputs.length){
    const x = inputs[ counter ]
    if (type(x) === 'Function'){
      if (isFalsy(x())){
        return false
      }
    } else if (isFalsy(x)){
      return false
    }
    counter++
  }
  return true
}

allType
allType(targetType: RambdaTypes): (...input: any[]) => boolean
It returns a function which will return true if all of its inputs arguments belong to targetType.
:boom:
targetTypeis one of the possible returns ofR.type
const targetType = 'String'
const result = R.allType(
  targetType
)('foo', 'bar', 'baz')
// => true
Try this R.allType example in Rambda REPL
R.allType source
import { type } from './type.js'
export function allType(targetType){
  return (...inputs) => {
    let counter = 0
    while (counter < inputs.length){
      if (type(inputs[ counter ]) !== targetType){
        return false
      }
      counter++
    }
    return true
  }
}

always
always<T>(x: T): (...args: unknown[]) => T
It returns function that always returns x.
const fn = R.always(7)
const result = fn()
// => 7
Try this R.always example in Rambda REPL
R.always source
export function always(x){
  return _ => x
}

and
Logical AND
R.and(true, true); // => true
R.and(false, true); // => false
R.and(true, 'foo'); // => 'foo'
Try this R.and example in Rambda REPL

any
any<T>(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.
const list = [1, 2, 3]
const predicate = x => x * x > 8
R.any(fn, list)
// => true
Try this R.any example in Rambda REPL
R.any source
export function any(predicate, list){
  if (arguments.length === 1) return _list => any(predicate, _list)
  let counter = 0
  while (counter < list.length){
    if (predicate(list[ counter ], counter)){
      return true
    }
    counter++
  }
  return false
}

anyFalse
anyFalse(...input: any[]): boolean
It returns true if any of inputs is falsy(empty objects and empty arrays are considered falsy).
R.anyFalse(1, {a: 1}, [1], () => false)
// => true
Try this R.anyFalse example in Rambda REPL
R.anyFalse source
import { isFalsy } from './_internals/isFalsy.js'
import { type } from './type.js'
export function anyFalse(...inputs){
  let counter = 0
  while (counter < inputs.length){
    const x = inputs[ counter ]
    if (type(x) === 'Function'){
      if (isFalsy(x())){
        return true
      }
    } else if (isFalsy(x)){
      return true
    }
    counter++
  }
  return false
}

anyPass
anyPass<T>(predicates: ((x: T) => boolean)[]): (input: T) => boolean
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.
const isBig = x => x > 20
const isOdd = x => x % 2 === 1
const input = 11
const fn = R.anyPass(
  [isBig, isOdd]
)
const result = fn(input) 
// => true
Try this R.anyPass example in Rambda REPL
R.anyPass source
export function anyPass(predicates){
  return (...input) => {
    let counter = 0
    while (counter < predicates.length){
      if (predicates[ counter ](...input)){
        return true
      }
      counter++
    }
    return false
  }
}

anyTrue
anyTrue(...input: any[]): boolean
It returns true if any of inputs arguments are truthy(empty objects and empty arrays are considered falsy).
R.anyTrue(0, null, [], {}, '', () => true)
// => true
Try this R.anyTrue example in Rambda REPL
R.anyTrue source
import { isTruthy } from './_internals/isTruthy.js'
import { type } from './type.js'
export function anyTrue(...inputs){
  let counter = 0
  while (counter < inputs.length){
    const x = inputs[ counter ]
    if (type(x) === 'Function'){
      if (isTruthy(x())){
        return true
      }
    } else if (isTruthy(x)){
      return true
    }
    counter++
  }
  return false
}

anyType
anyType(targetType: RambdaTypes): (...input: any[]) => boolean
It returns a function which will return true if at least one of its inputs arguments belongs to targetType.
targetType is one of the possible returns of R.type
:boom:
targetTypeis one of the possible returns ofR.type
const targetType = 'String'
const result = R.anyType(
  targetType
)(1, {}, 'foo')
// => true
Try this R.anyType example in Rambda REPL
R.anyType source
import { type } from './type.js'
export function anyType(targetType){
  return (...inputs) => {
    let counter = 0
    while (counter < inputs.length){
      if (type(inputs[ counter ]) === targetType){
        return true
      }
      counter++
    }
    return false
  }
}

append
append<T>(x: T, list: T[]): T[]
It adds element x at the end of list.
const x = 'foo'
const result = R.append(x, ['bar', 'baz'])
// => ['bar', 'baz', 'foo']
Try this R.append example in Rambda REPL
R.append source
import { cloneList } from './_internals/cloneList.js'
export function append(x, input){
  if (arguments.length === 1) return _input => append(x, _input)
  if (typeof input === 'string') return input.split('').concat(x)
  const clone = cloneList(input)
  clone.push(x)
  return clone
}

apply
apply<T = any>(fn: (...args: any[]) => T, args: any[]): T
It applies function fn to the list of arguments.
This is useful for creating a fixed-arity function from a variadic function. fn should be a bound function if context is significant.
const result = R.apply(Math.max, [42, -Infinity, 1337])
// => 1337
Try this R.apply example in Rambda REPL
R.apply source
export function apply(fn, args){
  if (arguments.length === 1){
    return _args => apply(fn, _args)
  }
  return fn.apply(this, args)
}

applyDiff
applyDiff<Output>(rules: ApplyDiffRule[], obj: object): Output
It changes paths in an object according to a list of operations. Valid operations are add, update and delete. Its use-case is while writing tests and you need to change the test data.
Note, that you cannot use update operation, if the object path is missing in the input object.
Also, you cannot use add operation, if the object path has a value.
const obj = {a: {b:1, c:2}}
const rules = [
  {op: 'remove', path: 'a.c'},
  {op: 'add', path: 'a.d', value: 4},
  {op: 'update', path: 'a.b', value: 2},
]
const result = R.applyDiff(rules, Record<string, unknown>)
const expected = {a: {b: 2, d: 4}}
// => `result` is equal to `expected`
Try this R.applyDiff example in Rambda REPL
R.applyDiff source
import { createPath } from './_internals/createPath.js'
import { assocPath } from './assocPath.js'
import { path as pathModule } from './path.js'
const ALLOWED_OPERATIONS = [ 'remove', 'add', 'update' ]
export function removeAtPath(path, obj){
  const p = createPath(path)
  const len = p.length
  if (len === 0) return
  if (len === 1) return delete obj[ p[ 0 ] ]
  if (len === 2) return delete obj[ p[ 0 ] ][ p[ 1 ] ]
  if (len === 3) return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ]
  if (len === 4) return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ]
  if (len === 5) return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ]
  if (len === 6){
    return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ]
  }
  if (len === 7){
    return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ][ p[ 6 ] ]
  }
  if (len === 8){
    return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ][ p[ 6 ] ][ p[ 7 ] ]
  }
  if (len === 9){
    return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ][ p[ 6 ] ][ p[ 7 ] ][ p[ 8 ] ]
  }
  if (len === 10){
    return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ][ p[ 6 ] ][ p[ 7 ] ][ p[ 8 ] ][
      p[ 9 ]
    ]
  }
}
export function applyDiff(rules, obj){
  if (arguments.length === 1) return _obj => applyDiff(rules, _obj)
  let clone = { ...obj }
  rules.forEach(({ op, path, value }) => {
    if (!ALLOWED_OPERATIONS.includes(op)) return
    if (op === 'add' && path && value !== undefined){
      if (pathModule(path, obj)) return
      return clone = assocPath(
        path, value, clone
      )
    }
    if (op === 'remove'){
      if (pathModule(path, obj) === undefined) return
      return removeAtPath(path, clone)
    }
    if (op === 'update' && path && value !== undefined){
      if (pathModule(path, obj) === undefined) return
      return clone = assocPath(
        path, value, clone
      )
    }
  })
  return clone
}

applySpec
applySpec<Spec extends Record<string, AnyFunction>>(
  spec: Spec
): (
  ...args: Parameters<ValueOfRecord<Spec>>
) => { [Key in keyof Spec]: ReturnType<Spec[Key]> }
:boom: The currying in this function works best with functions with 4 arguments or less. (arity of 4)
const fn = R.applySpec({
  sum: R.add,
  nested: { mul: R.multiply }
})
const result = fn(2, 4) 
// => { sum: 6, nested: { mul: 8 } }
Try this R.applySpec example in Rambda REPL
R.applySpec source
import { _isArray } from './_internals/_isArray.js'
// recursively traverse the given spec object to find the highest arity function
export function __findHighestArity(spec, max = 0){
  for (const key in spec){
    if (spec.hasOwnProperty(key) === false || key === 'constructor') continue
    if (typeof spec[ key ] === 'object'){
      max = Math.max(max, __findHighestArity(spec[ key ]))
    }
    if (typeof spec[ key ] === 'function'){
      max = Math.max(max, spec[ key ].length)
    }
  }
  return max
}
function __filterUndefined(){
  const defined = []
  let i = 0
  const l = arguments.length
  while (i < l){
    if (typeof arguments[ i ] === 'undefined') break
    defined[ i ] = arguments[ i ]
    i++
  }
  return defined
}
function __applySpecWithArity(
  spec, arity, cache
){
  const remaining = arity - cache.length
  if (remaining === 1)
    return x =>
      __applySpecWithArity(
        spec, arity, __filterUndefined(...cache, x)
      )
  if (remaining === 2)
    return (x, y) =>
      __applySpecWithArity(
        spec, arity, __filterUndefined(
          ...cache, x, y
        )
      )
  if (remaining === 3)
    return (
      x, y, z
    ) =>
      __applySpecWithArity(
        spec, arity, __filterUndefined(
          ...cache, x, y, z
        )
      )
  if (remaining === 4)
    return (
      x, y, z, a
    ) =>
      __applySpecWithArity(
        spec,
        arity,
        __filterUndefined(
          ...cache, x, y, z, a
        )
      )
  if (remaining > 4)
    return (...args) =>
      __applySpecWithArity(
        spec, arity, __filterUndefined(...cache, ...args)
      )
  // handle spec as Array
  if (_isArray(spec)){
    const ret = []
    let i = 0
    const l = spec.length
    for (; i < l; i++){
      // handle recursive spec inside array
      if (typeof spec[ i ] === 'object' || _isArray(spec[ i ])){
        ret[ i ] = __applySpecWithArity(
          spec[ i ], arity, cache
        )
      }
      // apply spec to the key
      if (typeof spec[ i ] === 'function'){
        ret[ i ] = spec[ i ](...cache)
      }
    }
    return ret
  }
  // handle spec as Object
  const ret = {}
  // apply callbacks to each property in the spec object
  for (const key in spec){
    if (spec.hasOwnProperty(key) === false || key === 'constructor') continue
    // apply the spec recursively
    if (typeof spec[ key ] === 'object'){
      ret[ key ] = __applySpecWithArity(
        spec[ key ], arity, cache
      )
      continue
    }
    // apply spec to the key
    if (typeof spec[ key ] === 'function'){
      ret[ key ] = spec[ key ](...cache)
    }
  }
  return ret
}
export function applySpec(spec, ...args){
  // get the highest arity spec function, cache the result and pass to __applySpecWithArity
  const arity = __findHighestArity(spec)
  if (arity === 0){
    return () => ({})
  }
  const toReturn = __applySpecWithArity(
    spec, arity, args
  )
  return toReturn
}

assoc
assoc<T, U, K extends string>(prop: K, val: T, obj: U): Record<K, T> & Omit<U, K>
It makes a shallow clone of obj with setting or overriding the property prop with newValue.
:boom: This copies and flattens prototype properties onto the new object as well. All non-primitive properties are copied by reference.
R.assoc('c', 3, {a: 1, b: 2})
// => {a: 1, b: 2, c: 3}
Try this R.assoc example in Rambda REPL
R.assoc source
import { curry } from './curry.js'
function assocFn(
  prop, newValue, obj
){
  return Object.assign(
    {}, obj, { [ prop ] : newValue }
  )
}
export const assoc = curry(assocFn)

assocPath
assocPath<Output>(path: Path, newValue: any, obj: object): Output
It makes a shallow clone of obj with setting or overriding with newValue the property found with path.
const path = 'b.c'
const newValue = 2
const obj = { a: 1 }
R.assocPath(path, newValue, Record<string, unknown>)
// => { a : 1, b : { c : 2 }}
Try this R.assocPath example in Rambda REPL
R.assocPath source
import { _isArray } from './_internals/_isArray.js'
import { _isInteger } from './_internals/_isInteger.js'
import { cloneList } from './_internals/cloneList.js'
import { assoc } from './assoc.js'
import { curry } from './curry.js'
function assocPathFn(
  path, newValue, input
){
  const pathArrValue =
    typeof path === 'string' ?
      path.split('.').map(x => _isInteger(Number(x)) ? Number(x) : x) :
      path
  if (pathArrValue.length === 0){
    return newValue
  }
  const index = pathArrValue[ 0 ]
  if (pathArrValue.length > 1){
    const condition =
      typeof input !== 'object' ||
      input === null ||
      !input.hasOwnProperty(index)
    const nextinput = condition ?
      _isInteger(pathArrValue[ 1 ]) ?
        [] :
        {} :
      input[ index ]
    newValue = assocPathFn(
      Array.prototype.slice.call(pathArrValue, 1),
      newValue,
      nextinput
    )
  }
  if (_isInteger(index) && _isArray(input)){
    const arr = cloneList(input)
    arr[ index ] = newValue
    return arr
  }
  return assoc(
    index, newValue, input
  )
}
export const assocPath = curry(assocPathFn)

bind
bind<F extends AnyFunction, T>(fn: F, thisObj: T): (...args: Parameters<F>) => ReturnType<F>
Creates a function that is bound to a context.
:boom: R.bind does not provide the additional argument-binding capabilities of
Function.prototype.bind.
const log = R.bind(console.log, console)
const result = R.pipe(
  R.assoc('a', 2), 
  R.tap(log), 
  R.assoc('a', 3)
)({a: 1}); 
// => result - `{a: 3}`
// => console log - `{a: 2}`
Try this R.bind example in Rambda REPL
R.bind source
import { curryN } from './curryN.js'
export function bind(fn, thisObj){
  if (arguments.length === 1){
    return _thisObj => bind(fn, _thisObj)
  }
  return curryN(fn.length, (...args) => fn.apply(thisObj, args))
}

both
both(pred1: Pred, pred2: Pred): Pred
It returns a function with input argument.
This function will return true, if both firstCondition and secondCondition return true when input is passed as their argument.
const firstCondition = x => x > 10
const secondCondition = x => x < 20
const fn = R.both(firstCondition, secondCondition)
const result = [fn(15), fn(30)]
// => [true, false]
Try this R.both example in Rambda REPL
R.both source
export function both(f, g){
  if (arguments.length === 1) return _g => both(f, _g)
  return (...input) => f(...input) && g(...input)
}

chain
chain<T, U>(fn: (n: T) => U[], list: T[]): U[]
The method is also known as flatMap.
const duplicate = n => [ n, n ]
const list = [ 1, 2, 3 ]
const result = chain(duplicate, list)
// => [ 1, 1, 2, 2, 3, 3 ]
Try this R.chain example in Rambda REPL
R.chain source
export function chain(fn, list){
  if (arguments.length === 1){
    return _list => chain(fn, _list)
  }
  return [].concat(...list.map(fn))
}

clamp
Restrict a number input to be within min and max limits.
If input is bigger than max, then the result is max.
If input is smaller than min, then the result is min.
const result = [
  R.clamp(0, 10, 5), 
  R.clamp(0, 10, -1),
  R.clamp(0, 10, 11)
]
// => [5, 0, 10]
Try this R.clamp example in Rambda REPL

clone
It creates a deep copy of the input, which may contain (nested) Arrays and Objects, Numbers, Strings, Booleans and Dates.
const objects = [{a: 1}, {b: 2}];
const objectsClone = R.clone(objects);
const result = [
  R.equals(objects, objectsClone),
  R.equals(objects[0], objectsClone[0]),
] // => [ true, true ]
Try this R.clone example in Rambda REPL

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).
const origin = x => x > 5
const inverted = complement(origin)
const result = [
  origin(7),
  inverted(7)
] => [ true, false ]
Try this R.complement example in Rambda REPL

compose
It performs right-to-left function composition.
const result = R.compose(
  R.map(x => x * 2),
  R.filter(x => x > 2)
)([1, 2, 3, 4])
// => [6, 8]
Try this R.compose example in Rambda REPL

composeAsync
composeAsync<Out>(
  ...fns: (Async<any> | Func<any>)[]
): (input: any) => Promise<Out>
Asynchronous version of R.compose
:boom: It doesn't work with promises or function returning promises such as
const foo = input => new Promise(...).
const add = async x => {
  await R.delay(100)
  return x + 1
}
const multiply = async x => {
  await R.delay(100)
  return x * 2 
}
const result = await R.composeAsync(
  add,
  multiply
)(1)
// `result` resolves to `3`
Try this R.composeAsync example in Rambda REPL
R.composeAsync source
import { type } from './type.js'
export function composeAsync(...inputArguments){
  return async function (startArgument){
    let argumentsToPass = startArgument
    while (inputArguments.length !== 0){
      const fn = inputArguments.pop()
      const typeFn = type(fn)
      if (typeFn === 'Async'){
        argumentsToPass = await fn(argumentsToPass)
      } else {
        argumentsToPass = fn(argumentsToPass)
        if (type(argumentsToPass) === 'Promise'){
          argumentsToPass = await argumentsToPass
        }
      }
    }
    return argumentsToPass
  }
}

concat
It returns a new string or array, which is the result of merging x and y.
R.concat([1, 2])([3, 4]) // => [1, 2, 3, 4]
R.concat('foo', 'bar') // => 'foobar'
Try this R.concat example in Rambda REPL

cond
It takes list with conditions and returns a new function fn that expects input as argument.
This function will start evaluating the conditions in order to find the first winner(order of conditions matter).
The winner is this condition, which left side returns true when input is its argument. Then the evaluation of the right side of the winner will be the final result.
If no winner is found, then fn returns undefined.
const fn = R.cond([
  [ x => x > 25, R.always('more than 25') ],
  [ x => x > 15, R.always('more than 15') ],
  [ R.T, x => `${x} is nothing special` ],
])
const result = [
  fn(30),
  fn(20),
  fn(10),
] 
// => ['more than 25', 'more than 15', '10 is nothing special']
Try this R.cond example in Rambda REPL

contains
contains<T, U>(target: T, compareTo: U): boolean
It returns true if all of target object properties are R.equal to compareTo object.
const result = R.contains({a:1}, {a:1, b:2})
// => true
Try this R.contains example in Rambda REPL
R.contains source
import { equals } from './equals.js'
export function contains(target, toCompare){
  if (arguments.length === 1){
    return _toCompare => contains(target, _toCompare)
  }
  let willReturn = true
  Object.keys(target).forEach(prop => {
    if (!willReturn) return
    if (
      toCompare[ prop ] === undefined ||
      !equals(target[ prop ], toCompare[ prop ])
    ){
      willReturn = false
    }
  })
  return willReturn
}

converge
Accepts a converging function and a list of branching functions and returns a new function. When invoked, this new function is applied to some arguments, each branching function is applied to those same arguments. The results of each branching function are passed as arguments to the converging function to produce the return value.
:boom: Explanation is taken from
Ramdadocumentation
const result = R.converge(R.multiply)([ R.add(1), R.add(3) ])(2)
// => 15
Try this R.converge example in Rambda REPL

count
It counts how many times predicate function returns true, when supplied with iteration of list.
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

countBy
countBy<T extends unknown>(transformFn: (x: T) => any, list: T[]): Record<string, number>
It counts elements in a list after each instance of the input list is passed through transformFn function.
const list = [ 'a', 'A', 'b', 'B', 'c', 'C' ]
const result = countBy(R.toLower, list)
const expected = { a: 2, b: 2, c: 2 }
// => `result` is equal to `expected`
Try this R.countBy example in Rambda REPL
R.countBy source
export function countBy(fn, list){
  if (arguments.length === 1){
    return _list => countBy(fn, _list)
  }
  const willReturn = {}
  list.forEach(item => {
    const key = fn(item)
    if (!willReturn[ key ]){
      willReturn[ key ] = 1
    } else {
      willReturn[ key ]++
    }
  })
  return willReturn
}

curry
It expects a function as input and returns its curried version.
const fn = (a, b, c) => a + b + c
const curried = R.curry(fn)
const sum = curried(1,2)
const result = sum(3) // => 6
Try this R.curry example in Rambda REPL

curryN
It returns a curried equivalent of the provided function, with the specified arity.

debounce
debounce<T, U>(fn: (input: T) => U, ms: number, immediate?: boolean): (input: T) => void
let counter = 0
const increment = () => {
  counter++
}
const debounced = R.debounce(increment, 1000)
async function fn(){
  debounced()
  await R.delay(500)
  debounced()
  await R.delay(800)
  console.log(counter) // => 0
  await R.delay(1200)
  console.log(counter) // => 1
  return counter
}
const result = await fn()
// `result` resolves to `1`
Try this R.debounce example in Rambda REPL
R.debounce source
export function debounce(
  func, ms, immediate = false
){
  let timeout
  return function (...input){
    const later = function (){
      timeout = null
      if (!immediate){
        return func.apply(null, input)
      }
    }
    const callNow = immediate && !timeout
    clearTimeout(timeout)
    timeout = setTimeout(later, ms)
    if (callNow){
      return func.apply(null, input)
    }
  }
}

dec
It decrements a number.

defaultTo
defaultTo<T>(defaultValue: T, input: T | null | undefined): 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: Rambda's defaultTo accept indefinite number of arguments when non curried, i.e.
R.defaultTo(2, foo, bar, baz).
R.defaultTo('foo', 'bar') // => 'bar'
R.defaultTo('foo', undefined) // => 'foo'
// Important - emtpy string is not falsy value(same as Ramda)
R.defaultTo('foo', '') // => 'foo'
Try this R.defaultTo example in Rambda REPL
R.defaultTo source
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
}

delay
delay(ms: number): Promise<'RAMBDAX_DELAY'>
setTimeout as a promise that resolves to R.DELAY variable after ms milliseconds.
const result = R.delay(1000)
// `result` resolves to `RAMBDAX_DELAY`
Try this R.delay example in Rambda REPL
R.delay source
export const DELAY = 'RAMBDAX_DELAY'
export function delay(ms){
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(DELAY)
    }, ms)
  })
}

deletePath
deletePath<T>(path: string): T
R.deletePath source
import { createPath } from './_internals/createPath.js'
import { assocPath } from './assocPath.js'
import { path as pathModule } from './path.js'
function removeProperty(prop, obj){
  const toReturn = {}
  Object.keys(obj).forEach(key => {
    if (key === prop) return
    toReturn[ key ] = obj[ key ]
  })
  return toReturn
}
export function deletePath(pathInput, obj){
  if (arguments.length === 1){
    return _obj => deletePath(pathInput, _obj)
  }
  const path = createPath(pathInput)
  if (path.length === 0){
    return obj
  }
  if (path.length === 1){
    return removeProperty(path[ 0 ], obj)
  }
  const lastIndex = path.length - 1
  const newPath = path.filter((item, i) => i !== lastIndex)
  const found = pathModule(newPath, obj)
  if (!found) return obj
  const newValue = deletePath(path[ lastIndex ], found)
  return assocPath(
    newPath, newValue, obj
  )
}

difference
difference<T>(a: T[], b: T[]): T[]
It returns the uniq set of all elements in the first list a not contained in the second list b.
R.equals is used to determine equality.
const a = [ 1, 2, 3, 4 ]
const b = [ 3, 4, 5, 6 ]
const result = difference(a, b)
// => [ 1, 2 ]
Try this R.difference example in Rambda REPL
R.difference source
import { includes } from './includes.js'
import { uniq } from './uniq.js'
export function difference(a, b){
  if (arguments.length === 1) return _b => difference(a, _b)
  return uniq(a).filter(aInstance => !includes(aInstance, b))
}

dissoc
It returns a new object that does not contain property prop.
R.dissoc('b', {a: 1, b: 2, c: 3})
// => {a: 1, c: 3}
Try this R.dissoc example in Rambda REPL

divide
R.divide(71, 100) // => 0.71
Try this R.divide example in Rambda REPL

drop
drop<T>(howMany: number, input: T[]): T[]
It returns howMany items dropped from beginning of list or string input.
R.drop(2, ['foo', 'bar', 'baz']) // => ['baz']
R.drop(2, 'foobar')  // => 'obar'
Try this R.drop example in Rambda REPL
R.drop source
export function drop(howManyToDrop, listOrString){
  if (arguments.length === 1) return _list => drop(howManyToDrop, _list)
  return listOrString.slice(howManyToDrop > 0 ? howManyToDrop : 0)
}

dropLast
dropLast<T>(howMany: number, input: T[]): T[]
It returns howMany items dropped from the end of list or string input.
R.dropLast(2, ['foo', 'bar', 'baz']) // => ['foo']
R.dropLast(2, 'foobar')  // => 'foob'
Try this R.dropLast example in Rambda REPL
R.dropLast source
export function dropLast(howManyToDrop, listOrString){
  if (arguments.length === 1){
    return _listOrString => dropLast(howManyToDrop, _listOrString)
  }
  return howManyToDrop > 0 ?
    listOrString.slice(0, -howManyToDrop) :
    listOrString.slice()
}

dropLastWhile
const list = [1, 2, 3, 4, 5];
const predicate = x => x >= 3
const result = dropLastWhile(predicate, list);
// => [1, 2]
Try this R.dropLastWhile example in Rambda REPL

dropRepeats
dropRepeats<T>(list: T[]): T[]
It removes any successive duplicates according to R.equals.
const result = R.dropRepeats([
  1, 
  1, 
  {a: 1}, 
  {a:1}, 
  1
])
// => [1, {a: 1}, 1]
Try this R.dropRepeats example in Rambda REPL
R.dropRepeats source
import { _isArray } from './_internals/_isArray.js'
import { equals } from './equals.js'
export function dropRepeats(list){
  if (!_isArray(list)){
    throw new Error(`${ list } is not a list`)
  }
  const toReturn = []
  list.reduce((prev, current) => {
    if (!equals(prev, current)){
      toReturn.push(current)
    }
    return current
  }, undefined)
  return toReturn
}

dropRepeatsWith
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

dropWhile
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

either
either(firstPredicate: Pred, secondPredicate: Pred): Pred
It returns a new predicate function from firstPredicate and secondPredicate inputs.
This predicate function will return true, if any of the two input predicates return true.
const firstPredicate = x => x > 10
const secondPredicate = x => x % 2 === 0
const predicate = R.either(firstPredicate, secondPredicate)
const result = [
  predicate(15),
  predicate(8),
  predicate(7),
]
// => [true, true, false]
Try this R.either example in Rambda REPL
R.either source
export function either(firstPredicate, secondPredicate){
  if (arguments.length === 1){
    return _secondPredicate => either(firstPredicate, _secondPredicate)
  }
  return (...input) =>
    Boolean(firstPredicate(...input) || secondPredicate(...input))
}

endsWith
endsWith(target: string, iterable: string): boolean
When iterable is a string, then it behaves as String.prototype.endsWith.
When iterable is a list, then it uses R.equals to determine if the target list ends in the same way as the given target.
const str = 'foo-bar'
const list = [{a:1}, {a:2}, {a:3}]
const result = [
  R.endsWith('bar', str),
  R.endsWith([{a:1}, {a:2}], list)
]
// => [true, true]
Try this R.endsWith example in Rambda REPL
R.endsWith source
import { _isArray } from './_internals/_isArray.js'
import { equals } from './equals.js'
export function endsWith(target, iterable){
  if (arguments.length === 1) return _iterable => endsWith(target, _iterable)
  if (typeof iterable === 'string'){
    return iterable.endsWith(target)
  }
  if (!_isArray(target)) return false
  const diff = iterable.length - target.length
  let correct = true
  const filtered = target.filter((x, index) => {
    if (!correct) return false
    const result = equals(x, iterable[ index + diff ])
    if (!result) correct = false
    return result
  })
  return filtered.length === target.length
}

eqProps
It returns true if property prop in obj1 is equal to property prop in obj2 according to R.equals.
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

equals
equals<T>(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
R.equals(
  [1, {a:2}, [{b: 3}]],
  [1, {a:2}, [{b: 3}]]
) // => true
Try this R.equals example in Rambda REPL
R.equals source
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 (![ 'Object', 'Array', 'NaN', 'RegExp' ].includes(typeOfValue))
    return list.lastIndexOf(valueToFind)
  const { length } = list
  let index = length
  let foundIndex = -1
  while (--index > -1 && foundIndex === -1){
    if (equals(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 (![ 'Object', 'Array', 'NaN', 'RegExp' ].includes(typeOfValue))
    return list.indexOf(valueToFind)
  let index = -1
  let foundIndex = -1
  const { length } = list
  while (++index < length && foundIndex === -1){
    if (equals(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 _equalsSets(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 parseError(maybeError){
  const typeofError = maybeError.__proto__.toString()
  if (![ 'Error', 'TypeError' ].includes(typeofError)) return []
  return [ typeofError, maybeError.message ]
}
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() ]
}
function equalsSets(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
}
export function equals(a, b){
  if (arguments.length === 1) return _b => equals(a, _b)
  const aType = type(a)
  if (aType !== type(b)) return false
  if (aType === 'Function'){
    return a.name === undefined ? false : a.name === b.name
  }
  if ([ 'NaN', 'Undefined', 'Null' ].includes(aType)) return true
  if (aType === 'Number'){
    if (Object.is(-0, a) !== Object.is(-0, b)) return false
    return a.toString() === b.toString()
  }
  if ([ 'String', 'Boolean' ].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 ] &&
          !equals(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
  } else if (bRegex[ 0 ]) return false
  const aDate = parseDate(a)
  const bDate = parseDate(b)
  if (aDate[ 0 ]){
    return bDate[ 0 ] ? aDate[ 1 ] === bDate[ 1 ] : false
  } else if (bDate[ 0 ]) return false
  const aError = parseError(a)
  const bError = parseError(b)
  if (aError[ 0 ]){
    return bError[ 0 ] ?
      aError[ 0 ] === bError[ 0 ] && aError[ 1 ] === bError[ 1 ] :
      false
  }
  if (aType === 'Set'){
    return _equalsSets(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 && !equals(aValue, bValue)){
          loopObjectFlag = false
        }
      }
    })
    return loopObjectFlag
  }
  return false
}

evolve
evolve<T, U>(rules: ((x: T) => U)[], list: T[]): U[]
It takes object or array of functions as set of rules. These rules are applied to the iterable input to produce the result.
:boom: Error handling of this method differs between Ramda and Rambda. Ramda for some wrong inputs returns result and for other - it returns one of the inputs. Rambda simply throws when inputs are not correct. Full details for this mismatch are listed in
source/_snapshots/evolve.spec.js.snapfile.
const rules = {
  foo : add(1),
  bar : add(-1),
}
const input = {
  a   : 1,
  foo : 2,
  bar : 3,
}
const result = evolve(rules, input)
const expected = {
  a   : 1,
  foo : 3,
  bar : 2,
})
// => `result` is equal to `expected`
Try this R.evolve example in Rambda REPL
R.evolve source
import { _isArray } from './_internals/_isArray.js'
import { mapArray, mapObject } from './map.js'
import { type } from './type.js'
export function evolveArray(rules, list){
  return mapArray(
    (x, i) => {
      if (type(rules[ i ]) === 'Function'){
        return rules[ i ](x)
      }
      return x
    },
    list,
    true
  )
}
export function evolveObject(rules, iterable){
  return mapObject((x, prop) => {
    if (type(x) === 'Object'){
      const typeRule = type(rules[ prop ])
      if (typeRule === 'Function'){
        return rules[ prop ](x)
      }
      if (typeRule === 'Object'){
        return evolve(rules[ prop ], x)
      }
      return x
    }
    if (type(rules[ prop ]) === 'Function'){
      return rules[ prop ](x)
    }
    return x
  }, iterable)
}
export function evolve(rules, iterable){
  if (arguments.length === 1){
    return _iterable => evolve(rules, _iterable)
  }
  const rulesType = type(rules)
  const iterableType = type(iterable)
  if (iterableType !== rulesType){
    throw new Error('iterableType !== rulesType')
  }
  if (![ 'Object', 'Array' ].includes(rulesType)){
    throw new Error(`'iterable' and 'rules' are from wrong type ${ rulesType }`)
  }
  if (iterableType === 'Object'){
    return evolveObject(rules, iterable)
  }
  return evolveArray(rules, iterable)
}

excludes
Opposite of R.includes
R.equals is used to determine equality.
const result = [
  R.excludes('ar', 'foo'),
  R.excludes({a: 2}, [{a: 1}])
]
// => [true, true ]
Try this R.excludes example in Rambda REPL

F
F(): boolean
F() // => false
Try this R.F example in Rambda REPL
R.F source
export function F(){
  return false
}

filter
filter<T>(predicate: Predicate<T>): (input: T[]) => T[]
It filters list or object input using a predicate function.
const list = [3, 4, 3, 2]
const listPredicate = x => x > 2
const object = {abc: 'fo', xyz: 'bar', baz: 'foo'}
const objectPredicate = (x, prop) => x.length + prop.length > 5
const result = [
  R.filter(listPredicate, list),
  R.filter(objectPredicate, object)
]
// => [ [3, 4], { xyz: 'bar', baz: 'foo'} ]
Try this R.filter example in Rambda REPL
R.filter source
import { _isArray } from './_internals/_isArray.js'
export function filterObject(predicate, obj){
  const willReturn = {}
  for (const prop in obj){
    if (predicate(
      obj[ prop ], prop, obj
    )){
      willReturn[ prop ] = obj[ prop ]
    }
  }
  return willReturn
}
export function filterArray(
  predicate, list, indexed = false
){
  let index = 0
  const len = list.length
  const willReturn = []
  while (index < len){
    const predicateResult = indexed ?
      predicate(list[ index ], index) :
      predicate(list[ index ])
    if (predicateResult){
      willReturn.push(list[ index ])
    }
    index++
  }
  return willReturn
}
export function filter(predicate, iterable){
  if (arguments.length === 1)
    return _iterable => filter(predicate, _iterable)
  if (!iterable){
    throw new Error('Incorrect iterable input')
  }
  if (_isArray(iterable)) return filterArray(
    predicate, iterable, false
  )
  return filterObject(predicate, iterable)
}

filterArray
filterArray<T>(predicate: Predicate<T>): (input: T[]) => T[]
const result = R.filterArray(
  x => x > 1,
  [1, 2, 3]
)
// => [1, 3]
Try this R.filterArray example in Rambda REPL

filterAsync
filterAsync<T>(fn: AsyncPredicate<T>, list: T[]): Promise<T[]>
Asynchronous version of R.filter
const predicate = async x => {
  await R.delay(100)
  return x % 2 === 1
}
const result = await R.filterAsync(predicate, [ 1, 2, 3 ])
// => [ 1, 3 ]
Try this R.filterAsync example in Rambda REPL
R.filterAsync source
import { _isArray } from './_internals/_isArray.js'
import { filter } from './filter.js'
import { mapAsync } from './mapAsync.js'
export function filterAsyncFn(predicate, listOrObject){
  return new Promise((resolve, reject) => {
    mapAsync(predicate, listOrObject)
      .then(predicateResult => {
        if (_isArray(predicateResult)){
          const filtered = listOrObject.filter((_, i) => predicateResult[ i ])
          return resolve(filtered)
        }
        const filtered = filter((_, prop) => predicateResult[ prop ],
          listOrObject)
        return resolve(filtered)
      })
      .catch(reject)
  })
}
export function filterAsync(predicate, listOrObject){
  if (arguments.length === 1){
    return async _listOrObject => filterAsyncFn(predicate, _listOrObject)
  }
  return new Promise((resolve, reject) => {
    filterAsyncFn(predicate, listOrObject).then(resolve)
      .catch(reject)
  })
}

filterIndexed
Same as R.filter, but it passes index/property as second argument to the predicate, when looping over arrays/objects.

filterObject
filterObject<T>(predicate: ObjectPredicate<T>): (x: Dictionary<T>) => Dictionary<T>
const obj = {a: 1, b:2}
const result = R.filterObject(
  x => x > 1,
  obj
)
// => {b: 2}
Try this R.filterObject example in Rambda REPL

find
find<T>(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.
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
R.find source
export function find(predicate, list){
  if (arguments.length === 1) return _list => find(predicate, _list)
  let index = 0
  const len = list.length
  while (index < len){
    const x = list[ index ]
    if (predicate(x)){
      return x
    }
    index++
  }
}

findAsync
Asynchronous version of R.find.
const predicate = x => {
  await R.delay(100)
  return R.type(x.foo) === 'Number'
}
const list = [{foo: 'bar'}, {foo: 1}]
const result = await R.findAsync(predicate, list)
// => {foo: 1}
Try this R.findAsync example in Rambda REPL

findIndex
findIndex<T>(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.
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
R.findIndex source
export function findIndex(predicate, list){
  if (arguments.length === 1) return _list => findIndex(predicate, _list)
  const len = list.length
  let index = -1
  while (++index < len){
    if (predicate(list[ index ])){
      return index
    }
  }
  return -1
}

findLast
findLast<T>(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.
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
R.findLast source
export function findLast(predicate, list){
  if (arguments.length === 1) return _list => findLast(predicate, _list)
  let index = list.length
  while (--index >= 0){
    if (predicate(list[ index ])){
      return list[ index ]
    }
  }
  return undefined
}

findLastIndex
findLastIndex<T>(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.
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
R.findLastIndex source
export function findLastIndex(fn, list){
  if (arguments.length === 1) return _list => findLastIndex(fn, _list)
  let index = list.length
  while (--index >= 0){
    if (fn(list[ index ])){
      return index
    }
  }
  return -1
}

flatten
flatten<T>(list: any[]): T[]
It deeply flattens an array.
const result = R.flatten([
  1, 
  2, 
  [3, 30, [300]], 
  [4]
])
// => [ 1, 2, 3, 30, 300, 4 ]
Try this R.flatten example in Rambda REPL
R.flatten source
import { _isArray } from './_internals/_isArray.js'
export function flatten(list, input){
  const willReturn = input === undefined ? [] : input
  for (let i = 0; i < list.length; i++){
    if (_isArray(list[ i ])){
      flatten(list[ i ], willReturn)
    } else {
      willReturn.push(list[ i ])
    }
  }
  return willReturn
}

flattenObject
It transforms object to object where each value is represented with its path.

flip
It returns function which calls fn with exchanged first and second argument.
:boom: Rambda's flip will throw if the arity of the input function is greater or equal to 5.
const subtractFlip = R.flip(R.subtract)
const result = [
  subtractFlip(1,7),
  R.subtract(1, 6)
]  
// => [6, -6]
Try this R.flip example in Rambda REPL

forEach
forEach<T>(fn: Iterator<T, void>, list: T[]): T[]
It applies iterable function over all members of list and returns list.
:boom: It works with objects, unlike
Ramda.
const sideEffect = {}
const result = R.forEach(
  x => sideEffect[`foo${x}`] = x
)([1, 2])
sideEffect // => {foo1: 1, foo2: 2}
result // => [1, 2]
Try this R.forEach example in Rambda REPL
R.forEach source
import { _isArray } from './_internals/_isArray.js'
import { _keys } from './_internals/_keys.js'
export function forEach(fn, list){
  if (arguments.length === 1) return _list => forEach(fn, _list)
  if (list === undefined){
    return
  }
  if (_isArray(list)){
    let index = 0
    const len = list.length
    while (index < len){
      fn(list[ index ])
      index++
    }
  } else {
    let index = 0
    const keys = _keys(list)
    const len = keys.length
    while (index < len){
      const key = keys[ index ]
      fn(
        list[ key ], key, list
      )
      index++
    }
  }
  return list
}

forEachIndexed

fromPairs
It transforms a listOfPairs to an object.
const listOfPairs = [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', [ 3, 4 ] ] ]
const expected = {
  a : 1,
  b : 2,
  c : [ 3, 4 ],
}
const result = R.fromPairs(listOfPairs)
// => `result` is equal to `expected`
Try this R.fromPairs example in Rambda REPL

getter
getter<T>(keyOrKeys: string | string[] | undefined): T
The set of methods R.setter, R.getter and R.reset allow different parts of your logic to access comminicate indirectly via shared cache object.
Usually these methods show that you might need to refactor to classes. Still, they can be helpful meanwhile.
R.getter: It provides access to the cache object. If undefined is used as a key, this method will return the whole cache object. If string is passed, then it will return cache value for this key. If array of string is passed, then it assume that this is array of keys and it will return the corresponding cache values for these keys.
R.setter: It allows cache object's keys to be changed. You can either set individual key-value pairs with R.setter(key, value) or you pass directly object, which will be merged with the cache object.
R.reset: It resets the cache object.
R.setter('foo','bar')
R.setter('a', 1)
R.getter(['foo','a']) // => {foo: 'bar', a: 1}
R.setter('a', 2)
R.getter('a') // => 2
R.reset()
R.getter('a') // => undefined
Try this R.getter example in Rambda REPL
R.getter source
import { mergeRight } from './mergeRight.js'
import { pick } from './pick.js'
import { type } from './type.js'
let holder = {}
/**
 * Pass string to get value
 * Pass array to get object of values
 * Pass undefined to get all data
 */
export function getter(key){
  const typeKey = type(key)
  if (typeKey === 'String') return holder[ key ]
  if (typeKey === 'Array') return pick(key, holder)
  return holder
}
export function setter(maybeKey, maybeValue){
  const typeKey = type(maybeKey)
  const typeValue = type(maybeValue)
  if (typeKey === 'String'){
    if (typeValue === 'Function'){
      return holder[ maybeKey ] = maybeValue(holder[ maybeKey ])
    }
    return holder[ maybeKey ] = maybeValue
  }
  if (typeKey !== 'Object') return
  holder = mergeRight(holder, maybeKey)
}
export function reset(){
  holder = {}
}

glue
glue(input: string, glueString?: string): string
It transforms multiline string to single line by gluing together the separate lines with the glueString and removing the empty spaces. By default glueString is equal to single space, so if that is what you need, then you can just pass a single argument.
const result = R.glue(`
  foo
  bar
  baz
`)
// => 'foo bar baz'
Try this R.glue example in Rambda REPL
R.glue source
export function glue(input, glueChar){
  return input
    .split('\n')
    .filter(x => x.trim().length > 0)
    .map(x => x.trim())
    .join(glueChar === undefined ? ' ' : glueChar)
}

groupBy
It splits list according to a provided groupFn function and returns an object.
const list = [ 'a', 'b', 'aa', 'bb' ]
const groupFn = x => x.length
const result = R.groupBy(groupFn, list)
// => { '1': ['a', 'b'], '2': ['aa', 'bb'] }
Try this R.groupBy example in Rambda REPL

groupWith
It returns separated version of list or string input, where separation is done with equality compareFn function.
const compareFn = (x, y) => x === y
const list = [1, 2, 2, 1, 1, 2]
const result = R.groupWith(isConsecutive, list)
// => [[1], [2,2], [1,1], [2]]
Try this R.groupWith example in Rambda REPL

has
has<T>(prop: string, obj: T): boolean
It returns true if obj has property prop.
const obj = {a: 1}
const result = [
  R.has('a', Record<string, unknown>),
  R.has('b', Record<string, unknown>)
]
// => [true, false]
Try this R.has example in Rambda REPL
R.has source
export function has(prop, obj){
  if (arguments.length === 1) return _obj => has(prop, _obj)
  if (!obj) return false
  return obj.hasOwnProperty(prop)
}

hasPath
hasPath<T>(
  path: string | string[],
  input: object
): boolean
It will return true, if input object has truthy path(calculated with R.path).
const path = 'a.b'
const pathAsArray = ['a', 'b']
const obj = {a: {b: []}}
const result = [
  R.hasPath(path, Record<string, unknown>),
  R.hasPath(pathAsArray, Record<string, unknown>),
  R.hasPath('a.c', Record<string, unknown>),
]
// => [true, true, false]
Try this R.hasPath example in Rambda REPL
R.hasPath source
import { path } from './path.js'
export function hasPath(pathInput, obj){
  if (arguments.length === 1){
    return objHolder => hasPath(pathInput, objHolder)
  }
  return path(pathInput, obj) !== undefined
}

head
head(input: string): string
It returns the first element of list or string input.
const result = [
  R.head([1, 2, 3]),
  R.head('foo') 
]
// => [1, 'f']
Try this R.head example in Rambda REPL
R.head source
export function head(listOrString){
  if (typeof listOrString === 'string') return listOrString[ 0 ] || ''
  return listOrString[ 0 ]
}

identical
It returns true if its arguments a and b are identical.
Otherwise, it returns false.
:boom: Values are identical if they reference the same memory.
NaNis identical toNaN;0and-0are not identical.
const objA = {a: 1};
const objB = {a: 1};
R.identical(objA, objA); // => true
R.identical(objA, objB); // => false
R.identical(1, 1); // => true
R.identical(1, '1'); // => false
R.identical([], []); // => false
R.identical(0, -0); // => false
R.identical(NaN, NaN); // => true
Try this R.identical example in Rambda REPL

identity
identity<T>(input: T): T
It just passes back the supplied input argument.
:boom: Logic
R.identity(7) // => 7
Try this R.identity example in Rambda REPL
R.identity source
export function identity(x){
  return x
}

ifElse
ifElse<T, TFiltered extends T, TOnTrueResult, TOnFalseResult>(
  pred: (a: T) => a is TFiltered,
  onTrue: (a: TFiltered) => TOnTrueResult,
  onFalse: (a: Exclude<T, TFiltered>) => TOnFalseResult,
): (a: T) => TOnTrueResult | TOnFalseResult
It expects condition, onTrue and onFalse functions as inputs and it returns a new function with example name of fn.
When fn`` is called with inputargument, it will return eitheronTrue(input)oronFalse(input)depending oncondition(input)` evaluation.
const fn = R.ifElse(
 x => x>10,
 x => x*2,
 x => x*10
)
const result = [ fn(8), fn(18) ]
// => [80, 36]
Try this R.ifElse example in Rambda REPL
R.ifElse source
import { curry } from './curry.js'
function ifElseFn(
  condition, onTrue, onFalse
){
  return (...input) => {
    const conditionResult =
      typeof condition === 'boolean' ? condition : condition(...input)
    if (conditionResult === true){
      return onTrue(...input)
    }
    return onFalse(...input)
  }
}
export const ifElse = curry(ifElseFn)

ifElseAsync
ifElseAsync<T, U>(
  condition: (x: T) => Promise<boolean>, 
  onTrue: (x: T) => U, 
  onFalse: (x: T) => U, 
  ): (x: T) => Promise<U>
Asynchronous version of R.ifElse. Any of condition, ifFn and elseFn can be either asynchronous or synchronous function.
const condition = async x => {
  await R.delay(100)
  return x > 1
}
const ifFn = async x => {
  await R.delay(100)
  return x + 1
}
const elseFn = async x => {
  await R.delay(100)
  return x - 1
}
const result = await R.ifElseAsync(
  condition,
  ifFn,
  elseFn  
)(1)
// => 0
Try this R.ifElseAsync example in Rambda REPL
R.ifElseAsync source
function createThenable(fn){
  return async function (...input){
    return fn(...input)
  }
}
export function ifElseAsync(
  condition, ifFn, elseFn
){
  return (...inputs) =>
    new Promise((resolve, reject) => {
      const conditionPromise = createThenable(condition)
      const ifFnPromise = createThenable(ifFn)
      const elseFnPromise = createThenable(elseFn)
      conditionPromise(...inputs)
        .then(conditionResult => {
          const promised =
            conditionResult === true ? ifFnPromise : elseFnPromise
          promised(...inputs)
            .then(resolve)
            .catch(reject)
        })
        .catch(reject)
    })
}

inc
It increments a number.
R.inc(1) // => 2
Try this R.inc example in Rambda REPL

includes
includes(valueToFind: string, input: string[] | 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.
const result = [
  R.includes('oo', 'foo'),
  R.includes({a: 1}, [{a: 1}])
]
// => [true, true ]
Try this R.includes example in Rambda REPL
R.includes source
import { _isArray } from './_internals/_isArray.js'
import { _indexOf } from './equals.js'
export function includes(valueToFind, iterable){
  if (arguments.length === 1)
    return _iterable => includes(valueToFind, _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
}

indexBy
It generates object with properties provided by condition and values provided by list array.
If condition is a function, then all list members are passed through it.
If condition is a string, then all list members are passed through R.path(condition).
const list = [ {id: 10}, {id: 20} ]
const withFunction = R.indexBy(
  x => x.id,
  list
)
const withString = R.indexBy(
  'id',
  list
)
const result = [
  withFunction, 
  R.equals(withFunction, withString)
]
// => [ { 10: {id: 10}, 20: {id: 20} }, true ]
Try this R.indexBy example in Rambda REPL

indexOf
It returns the index of the first element of list equals to valueToFind.
If there is no such element, it returns -1.
:boom: It uses
R.equalsfor list of objects/arrays or nativeindexOffor any other case.
const list = [0, 1, 2, 3]
const result = [
  R.indexOf(2, list),
  R.indexOf(0, list)
]
// => [2, -1]
Try this R.indexOf example in Rambda REPL

init
init<T extends unknown[]>(input: T): T extends readonly [...infer U, any] ? U : [...T]
It returns all but the last element of list or string input.
const result = [
  R.init([1, 2, 3]) , 
  R.init('foo')  // => 'fo'
]
// => [[1, 2], 'fo']
Try this R.init example in Rambda REPL
R.init source
import baseSlice from './_internals/baseSlice.js'
export function init(listOrString){
  if (typeof listOrString === 'string') return listOrString.slice(0, -1)
  return listOrString.length ?
    baseSlice(
      listOrString, 0, -1
    ) :
    []
}

interpolate
interpolate(inputWithTags: string, templateArguments: object): string
It generages a new string from inputWithTags by replacing all {{x}} occurances with values provided by templateArguments.
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
R.interpolate source
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, templateInput){
  if (arguments.length === 1){
    return _templateInput => interpolate(input, _templateInput)
  }
  const occurrences = getOccurrences(input)
  if (occurrences === null) return input
  let inputHolder = input
  for (const occurrence of occurrences){
    const prop = getOccurrenceProp(occurrence)
    inputHolder = replace({
      inputHolder,
      prop,
      replacer : templateInput[ prop ],
    })
  }
  return inputHolder
}

intersection
It loops throw 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' ]".
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

intersperse
It adds a separator between members of list.
const list = [ 0, 1, 2, 3 ]
const separator = '|'
const result = intersperse(separator, list)
// => [0, '|', 1, '|', 2, '|', 3]
Try this R.intersperse example in Rambda REPL

is
It returns true if x is instance of targetPrototype.
const result = [
  R.is(String, 'foo'),  
  R.is(Array, 1)
]
// => [true, false]
Try this R.is example in Rambda REPL

isEmpty
isEmpty<T>(x: T): boolean
It returns true if x is empty.
const result = [
  R.isEmpty(''),
  R.isEmpty({ x : 0 })
]
// => [true, false]
Try this R.isEmpty example in Rambda REPL
R.isEmpty source
import { type } from './type.js'
export function isEmpty(input){
  const inputType = type(input)
  if ([ 'Undefined', 'NaN', 'Number', 'Null' ].includes(inputType))
    return false
  if (!input) return true
  if (inputType === 'Object'){
    return Object.keys(input).length === 0
  }
  if (inputType === 'Array'){
    return input.length === 0
  }
  return false
}

isNil
isNil(x: any): x is null | undefined
It returns true if x is either null or undefined.
const result = [
  R.isNil(null),
  R.isNil(1),
]
// => [true, false]
Try this R.isNil example in Rambda REPL
R.isNil source
export function isNil(x){
  return x === undefined || x === null
}

isPromise
isPromise(input: any): boolean

isType
isType(targetType: RambdaTypes, input: any): boolean
It returns true if targetType is equal to type of input according to R.type.
R.isType('Async',R.delay(1000))
// => true
Try this R.isType example in Rambda REPL
R.isType source
import { type } from './type.js'
export function isType(xType, x){
  if (arguments.length === 1){
    return xHolder => isType(xType, xHolder)
  }
  return type(x) === xType
}

isValid
isValid({input: object, schema: Schema}: IsValid): boolean
It checks if input is following schema specifications.
If validation fails, it returns false.
Please check the detailed explanation as it is hard to write a short description for this method.
:boom: Independently, somebody else came with very similar idea called superstruct
const input = {a: ['foo', 'bar']}
const invalidInput = {a: ['foo', 'bar', 1]}
const schema = {a: [String]}
const result = [
  R.isValid({schema, input}),
  R.isValid({schema, input: invalidInput})
]
// => [true, false]
Try this R.isValid example in Rambda REPL
R.isValid source
import { _isArray } from './_internals/_isArray.js'
import { all } from './all.js'
import { any } from './any.js'
import { includes } from './includes.js'
import { init } from './init.js'
import { test } from './test.js'
import { toLower } from './toLower.js'
import { type } from './type.js'
export function isPrototype(input){
  const currentPrototype = input.prototype
  const list = [ Number, String, Boolean, Promise ]
  let toReturn = false
  let counter = -1
  while (++counter < list.length && !toReturn){
    if (currentPrototype === list[ counter ].prototype) toReturn = true
  }
  return toReturn
}
export function prototypeToString(input){
  const currentPrototype = input.prototype
  const list = [ Number, String, Boolean, Promise ]
  const translatedList = [ 'Number', 'String', 'Boolean', 'Promise' ]
  let found
  let counter = -1
  while (++counter < list.length){
    if (currentPrototype === list[ counter ].prototype) found = counter
  }
  return translatedList[ found ]
}
const typesWithoutPrototype = [ 'any', 'promise', 'async', 'function' ]
export function fromPrototypeToString(rule){
  if (
    _isArray(rule) ||
    rule === undefined ||
    rule === null ||
    rule.prototype === undefined ||
    typesWithoutPrototype.includes(rule)
  ){
    return {
      rule,
      parsed : false,
    }
  }
  if (String.prototype === rule.prototype){
    return {
      rule   : 'string',
      parsed : true,
    }
  }
  if (Boolean.prototype === rule.prototype){
    return {
      rule   : 'boolean',
      parsed : true,
    }
  }
  if (Number.prototype === rule.prototype){
    return {
      rule   : 'number',
      parsed : true,
    }
  }
  return {
    rule   : type(rule.prototype).toLowerCase(),
    parsed : true,
  }
}
function getRuleAndType(schema, requirementRaw){
  const ruleRaw = schema[ requirementRaw ]
  const typeIs = type(ruleRaw)
  const { rule, parsed } = fromPrototypeToString(ruleRaw)
  return {
    rule     : rule,
    ruleType : parsed ? 'String' : typeIs,
  }
}
export function isValid({ input, schema }){
  if (input === undefined || schema === undefined) return false
  let flag = true
  const boom = boomFlag => {
    if (!boomFlag){
      flag = false
    }
  }
  for (const requirementRaw in schema){
    if (flag){
      const isOptional = requirementRaw.endsWith('?')
      const requirement = isOptional ? init(requirementRaw) : requirementRaw
      const { rule, ruleType } = getRuleAndType(schema, requirementRaw)
      const inputProp = input[ requirement ]
      const inputPropType = type(input[ requirement ])
      const ok = isOptional && inputProp !== undefined || !isOptional
      if (!ok || rule === 'any' && inputProp != null || rule === inputProp)
        continue
      if (ruleType === 'Object'){
        /**
         * This rule is standalone schema, so we recursevly call `isValid`
         */
        const isValidResult = isValid({
          input  : inputProp,
          schema : rule,
        })
        boom(isValidResult)
      } else if (ruleType === 'String'){
        /**
         * Rule is actual rule such as 'number', so the two types are compared
         */
        boom(toLower(inputPropType) === rule)
      } else if (typeof rule === 'function'){
        /**
         * Rule is function so we pass to it the input
         */
        boom(rule(inputProp))
      } else if (ruleType === 'Array' && inputPropType === 'String'){
        /**
         * Enum case | rule is like a: ['foo', 'bar']
         */
        boom(includes(inputProp, rule))
      } else if (
        ruleType === 'Array' &&
        rule.length === 1 &&
        inputPropType === 'Array'
      ){
        /**
         * 1. array of type | rule is like a: ['number']
         * 2. rule is like a: [{foo: 'string', bar: 'number'}]
         */
        const [ currentRule ] = rule
        const currentRuleType = type(currentRule)
        //Check if rule is invalid
        boom(currentRuleType === 'String' ||
            currentRuleType === 'Object' ||
            isPrototype(currentRule))
        if (currentRuleType === 'Object' && flag){
          /**
           * 2. rule is like a: [{from: 'string'}]
           */
          const isValidResult = all(inputPropInstance =>
            isValid({
              input  : inputPropInstance,
              schema : currentRule,
            }),
          inputProp)
          boom(isValidResult)
        } else if (flag){
          /**
           * 1. array of type
           */
          const actualRule =
            currentRuleType === 'String' ?
              currentRule :
              prototypeToString(currentRule)
          const isInvalidResult = any(inputPropInstance =>
            type(inputPropInstance).toLowerCase() !==
              actualRule.toLowerCase(),
          inputProp)
          boom(!isInvalidResult)
        }
      } else if (ruleType === 'RegExp' && inputPropType === 'String'){
        boom(test(rule, inputProp))
      } else {
        boom(false)
      }
    }
  }
  return flag
}

isValidAsync
isValidAsync(x: IsValidAsync): Promise<boolean>
Asynchronous version of R.isValid
const input = {a: 1, b: 2}
const invalidInput = {a: 1, b: 'foo'}
const schema = {a: Number, b: async x => {
  await R.delay(100)
  return typeof x === 'number'
}}
const result = await Promise.all([
  R.isValidAsync({schema, input}),
  R.isValidAsync({schema, input: invalidInput})
])
// => [true, false]
Try this R.isValidAsync example in Rambda REPL
R.isValidAsync source
import { forEach } from './forEach.js'
import { isPromise } from './isPromise.js'
import { isValid } from './isValid.js'
export async function isValidAsync({ schema, input }){
  const asyncSchema = {}
  const simpleSchema = {}
  forEach((rule, prop) => {
    if (isPromise(rule)){
      asyncSchema[ prop ] = rule
    } else {
      simpleSchema[ prop ] = rule
    }
  }, schema)
  if (Object.keys(asyncSchema).length === 0)
    return isValid({
      input,
      schema,
    })
  if (
    !isValid({
      input,
      schema : simpleSchema,
    })
  )
    return false
  let toReturn = true
  for (const singleRuleProp in asyncSchema){
    if (toReturn){
      const validated = await asyncSchema[ singleRuleProp ](input[ singleRuleProp ])
      if (!validated) toReturn = false
    }
  }
  return toReturn
}

join
join<T>(glue: string, list: T[]): string
It returns a string of all list instances joined with a glue.
R.join('-', [1, 2, 3])  // => '1-2-3'
Try this R.join example in Rambda REPL
R.join source
export function join(glue, list){
  if (arguments.length === 1) return _list => join(glue, _list)
  return list.join(glue)
}

juxt
juxt<A extends any[], R1>(fns: [(...a: A) => R1]): (...a: A) => [R1]
It applies list of function to a list of inputs.
const getRange = juxt([ Math.min, Math.max, Math.min ])
const result = getRange(
  3, 4, 9, -3
)
// => [-3, 9, -3]
Try this R.juxt example in Rambda REPL
R.juxt source
export function juxt(listOfFunctions){
  return (...args) => listOfFunctions.map(fn => fn(...args))
}

keys
keys<T extends object>(x: T): (keyof T)[]
It applies Object.keys over x and returns its keys.
R.keys({a:1, b:2})  // => ['a', 'b']
Try this R.keys example in Rambda REPL
R.keys source
export function keys(x){
  return Object.keys(x)
}

last
last(str: string): string
It returns the last element of input, as the input can be either a string or an array.
const result = [
  R.last([1, 2, 3]),
  R.last('foo'),
]
// => [3, 'o']
Try this R.last example in Rambda REPL
R.last source
export function last(listOrString){
  if (typeof listOrString === 'string'){
    return listOrString[ listOrString.length - 1 ] || ''
  }
  return listOrString[ listOrString.length - 1 ]
}

lastIndexOf
lastIndexOf<T>(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.
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
R.lastIndexOf source
import { _lastIndexOf } from './equals.js'
export function lastIndexOf(valueToFind, list){
  if (arguments.length === 1){
    return _list => _lastIndexOf(valueToFind, _list)
  }
  return _lastIndexOf(valueToFind, list)
}

length
length<T>(input: T[]): number
It returns the length property of list or string input.
const result = [
  R.length([1, 2, 3, 4]),
  R.length('foo'),
]
// => [4, 3]
Try this R.length example in Rambda REPL
R.length source
import { _isArray } from './_internals/_isArray.js'
export function length(x){
  if (_isArray(x)) return x.length
  if (typeof x === 'string') return x.length
  return NaN
}

lens
lens<T, U, V>(getter: (s: T) => U, setter: (a: U, s: T) => V): Lens
It returns a lens for the given getter and setter functions.
The getter gets the value of the focus; the setter sets the value of the focus.
The setter should not mutate the data structure.
const xLens = R.lens(R.prop('x'), R.assoc('x'));
R.view(xLens, {x: 1, y: 2}) // => 1
R.set(xLens, 4, {x: 1, y: 2}) // => {x: 4, y: 2}
R.over(xLens, R.negate, {x: 1, y: 2}) // => {x: -1, y: 2}
Try this R.lens example in Rambda REPL
R.lens source
export function lens(getter, setter){
  return function (functor){
    return function (target){
      return functor(getter(target)).map(focus => setter(focus, target))
    }
  }
}

lensEq
lensEq<T, U>(lens: Lens, target: T, input: U): boolean
It returns true if data structure focused by the given lens equals to the target value.
R.equals is used to determine equality.
:boom: Idea for this method comes from
ramda-adjunctlibrary
const list = [ 1, 2, 3 ]
const lens = R.lensIndex(0)
const result = R.lensEq(
  lens, 1, list
)
// => true
Try this R.lensEq example in Rambda REPL
R.lensEq source
import { curry } from './curry.js'
import { equals } from './equals.js'
import { view } from './view.js'
function lensEqFn(
  lens, target, input
){
  return equals(view(lens, input), target)
}
export const lensEq = curry(lensEqFn)

lensIndex
lensIndex(index: number): Lens
It returns a lens that focuses on specified index.
const list = ['a', 'b', 'c']
const headLens = R.lensIndex(0)
R.view(headLens, list) // => 'a'
R.set(headLens, 'x', list) // => ['x', 'b', 'c']
R.over(headLens, R.toUpper, list) // => ['A', 'b', 'c']
Try this R.lensIndex example in Rambda REPL
R.lensIndex source
import { lens } from './lens.js'
import { nth } from './nth.js'
import { update } from './update.js'
export function lensIndex(index){
  return lens(nth(index), update(index))
}

lensPath
lensPath(path: RamdaPath): Lens
It returns a lens that focuses on specified path.
const lensPath = R.lensPath(['x', 0, 'y'])
const input = {x: [{y: 2, z: 3}, {y: 4, z: 5}]}
R.view(lensPath, input) // => 2
R.set(lensPath, 1, input) 
// => {x: [{y: 1, z: 3}, {y: 4, z: 5}]}
R.over(xHeadYLens, R.negate, input) 
// => {x: [{y: -2, z: 3}, {y: 4, z: 5}]}
Try this R.lensPath example in Rambda REPL
R.lensPath source
import { assocPath } from './assocPath.js'
import { lens } from './lens.js'
import { path } from './path.js'
export function lensPath(key){
  return lens(path(key), assocPath(key))
}

lensProp
lensProp(prop: string): {
  <T, U>(obj: T): U
It returns a lens that focuses on specified property prop.
const xLens = R.lensProp('x');
const input = {x: 1, y: 2}
R.view(xLens, input) // => 1
R.set(xLens, 4, input) 
// => {x: 4, y: 2}
R.over(xLens, R.negate, input) 
// => {x: -1, y: 2}
Try this R.lensProp example in Rambda REPL
R.lensProp source
import { assoc } from './assoc.js'
import { lens } from './lens.js'
import { prop } from './prop.js'
export function lensProp(key){
  return lens(prop(key), assoc(key))
}

lensSatisfies
lensSatisfies<T, U>(predicate: (x: T) => boolean, lens: Lens, input: U): boolean
It returns true if data structure focused by the given lens satisfies the predicate.
:boom: Idea for this method comes from
ramda-adjunctlibrary
const fn = R.lensSatisfies(x => x > 5, R.lensIndex(0))
const result = [
  fn([10, 20, 30]),
  fn([1, 2, 3]),
]
// => [true, false]
Try this R.lensSatisfies example in Rambda REPL
R.lensSatisfies source
import { curry } from './curry.js'
import { view } from './view.js'
function lensSatisfiesFn(
  predicate, lens, input
){
  return Boolean(predicate(view(lens, input)))
}
export const lensSatisfies = curry(lensSatisfiesFn)

map
map<T, U>(fn: ObjectIterator<T, U>, iterable: Dictionary<T>): Dictionary<U>
It returns the result of looping through iterable with fn.
It works with both array and object.
:boom: Unlike Ramda's
map, here property and input object are passed as arguments tofn, wheniterableis an object.
const fn = x => x * 2
const fnWhenObject = (val, prop)=>{
  return `${prop}-${val}`
}
const iterable = [1, 2]
const obj = {a: 1, b: 2}
const result = [ 
  R.map(fn, list),
  R.map(fnWhenObject, Record<string, unknown>)
]
// => [ [1, 4], {a: 'a-1', b: 'b-2'}]
Try this R.map example in Rambda REPL
R.map source
import { _isArray } from './_internals/_isArray.js'
import { _keys } from './_internals/_keys.js'
export function mapArray(
  fn, list, isIndexed = false
){
  let index = 0
  const willReturn = Array(list.length)
  while (index < list.length){
    willReturn[ index ] = isIndexed ? fn(list[ index ], index) : fn(list[ index ])
    index++
  }
  return willReturn
}
export function mapObject(fn, obj){
  if (arguments.length === 1){
    return _obj => mapObject(fn, _obj)
  }
  let index = 0
  const keys = _keys(obj)
  const len = keys.length
  const willReturn = {}
  while (index < len){
    const key = keys[ index ]
    willReturn[ key ] = fn(
      obj[ key ], key, obj
    )
    index++
  }
  return willReturn
}
export const mapObjIndexed = mapObject
export function map(fn, iterable){
  if (arguments.length === 1) return _iterable => map(fn, _iterable)
  if (!iterable){
    throw new Error('Incorrect iterable input')
  }
  if (_isArray(iterable)) return mapArray(fn, iterable)
  return mapObject(fn, iterable)
}

mapArray
mapArray<T>(fn: Iterator<T, T>, iterable: T[]): T[]
const result = R.mapArray(x => x + 1, [1, 2])
// => [2, 3]
Try this R.mapArray example in Rambda REPL

mapAsync
mapAsync<T, K>(fn: AsyncIterable<T, K>, list: T[]): Promise<K[]>
Sequential asynchronous mapping with fn over members of list.
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
R.mapAsync source
import { _isArray } from './_internals/_isArray.js'
async function mapAsyncFn(fn, listOrObject){
  if (_isArray(listOrObject)){
    const willReturn = []
    let i = 0
    for (const a of listOrObject){
      willReturn.push(await fn(a, i++))
    }
    return willReturn
  }
  const willReturn = {}
  for (const prop in listOrObject){
    willReturn[ prop ] = await fn(listOrObject[ prop ], prop)
  }
  return willReturn
}
export function mapAsync(fn, listOrObject){
  if (arguments.length === 1){
    return async _listOrObject => mapAsyncFn(fn, _listOrObject)
  }
  return new Promise((resolve, reject) => {
    mapAsyncFn(fn, listOrObject).then(resolve)
      .catch(reject)
  })
}

mapAsyncLimit
mapAsyncLimit<T, K>(fn: AsyncIterable<T, K>, limit: number, list: T[]): Promise<K[]>
It is similar to R.mapFastAsync in that it uses Promise.all but not over the whole list, rather than with only slice from list with length limit.
:boom: For example usage, please check
R.mapAsyncLimittests.
R.mapAsyncLimit source
import { mapFastAsync, mapFastAsyncFn } from './mapFastAsync.js'
import { splitEvery } from './splitEvery.js'
async function mapAsyncLimitFn(
  iterable, limit, list
){
  if (list.length < limit) return mapFastAsync(iterable, list)
  const slices = splitEvery(limit, list)
  let toReturn = []
  for (const slice of slices){
    const iterableResult = await mapFastAsyncFn(iterable, slice)
    toReturn = [ ...toReturn, ...iterableResult ]
  }
  return toReturn
}
export function mapAsyncLimit(
  iterable, limit, list
){
  if (arguments.length === 2){
    return async _list => mapAsyncLimitFn(
      iterable, limit, _list
    )
  }
  return new Promise((resolve, reject) => {
    mapAsyncLimitFn(
      iterable, limit, list
    ).then(resolve)
      .catch(reject)
  })
}

mapcat
const result = R.mapcat()
// =>
Try this R.mapcat example in Rambda REPL

mapFastAsync
mapFastAsync<T, K>(fn: AsyncIterable<T, K>, list: T[]): Promise<K[]>
Parrallel asynchronous mapping with fn over members of list.
async function fn(x){
  await R.delay(1000)
  return x+1
}
const result = await R.mapFastAsync(fn, [1, 2, 3])
// `result` resolves after 1 second to `[2, 3, 4]`
Try this R.mapFastAsync example in Rambda REPL
R.mapFastAsync source
export async function mapFastAsyncFn(fn, arr){
  const promised = arr.map((a, i) => fn(a, i))
  return Promise.all(promised)
}
export function mapFastAsync(fn, arr){
  if (arguments.length === 1){
    return async holder => mapFastAsyncFn(fn, holder)
  }
  return new Promise((resolve, reject) => {
    mapFastAsyncFn(fn, arr).then(resolve)
      .catch(reject)
  })
}

mapIndexed
Same as R.map, but it passes index as second argument to the iterator, when looping over arrays.

mapKeys
mapKeys<T, U>(changeKeyFn: (x: string) => string, obj: { [key: string]: T}): U
It takes an object and returns a new object with changed keys according to changeKeyFn function.
const obj = {a: 1, b: 2}
const changeKeyFn = prop => `{prop}_foo`
const result = R.mapKeys(changeKeyFn, Record<string, unknown>)
// => {a_foo: 1, b_foo: 2}
Try this R.mapKeys example in Rambda REPL
R.mapKeys source
export function mapKeys(changeKeyFn, obj){
  if (arguments.length === 1) return _obj => mapKeys(changeKeyFn, _obj)
  const toReturn = {}
  Object.keys(obj).forEach(prop => toReturn[ changeKeyFn(prop) ] = obj[ prop ])
  return toReturn
}

mapObject
mapObject<T>(fn: ObjectIterator<T, T>, iterable: Dictionary<T>): Dictionary<T>
const result = R.mapObject(x => x + 1, {a:1, b:2})
// => {a:2, b:3}
Try this R.mapObject example in Rambda REPL

mapObjIndexed
It works the same way as R.map does for objects. It is added as Ramda also has this method.
const fn = (val, prop) => {
  return `${prop}-${val}`
}
const obj = {a: 1, b: 2}
const result = R.map(mapObjIndexed, Record<string, unknown>)
// => {a: 'a-1', b: 'b-2'}
Try this R.mapObjIndexed example in Rambda REPL

mapToObject
mapToObject<T, U>(fn: (input: T) => object|false, list: T[]): U
This method allows to generate an object from a list using input function fn.
This function must return either an object or false for every member of list input.
If false is returned, then this element of list will be skipped in the calculation of the result.
All of returned objects will be merged to generate the final result.
const list = [1, 2, 3, 12]
const fn = x => {
  if(x > 10) return false
  return x % 2 ? {[x]: x + 1}: {[x]: x + 10}
}
const result = mapToObject(fn, list)
const expected = {'1': 2, '2': 12, '3': 4}
// => `result` is equal to `expected`
Try this R.mapToObject example in Rambda REPL
R.mapToObject source
import { map } from './map.js'
import { mergeAll } from './mergeAll.js'
import { ok } from './ok.js'
import { type } from './type.js'
export function mapToObject(fn, list){
  if (arguments.length === 1){
    return listHolder => mapToObject(fn, listHolder)
  }
  ok(type(fn), type(list))('Function', 'Array')
  return mergeAll(map(fn, list))
}

mapToObjectAsync
mapToObjectAsync<T, U>(fn: (input: T) => Promise<object|false>, list: T[]): Promise<U>
Asynchronous version of R.mapToObject
R.mapToObjectAsync source
import { mapAsync } from './mapAsync.js'
export async function mapToObjectAsyncFn(fn, list){
  let toReturn = {}
  const innerIterable = async x => {
    const intermediateResult = await fn(x)
    if (intermediateResult === false) return
    toReturn = {
      ...toReturn,
      ...intermediateResult,
    }
  }
  await mapAsync(innerIterable, list)
  return toReturn
}
export function mapToObjectAsync(fn, list){
  if (arguments.length === 1){
    return async _list => mapToObjectAsyncFn(fn, _list)
  }
  return new Promise((resolve, reject) => {
    mapToObjectAsyncFn(fn, list).then(resolve)
      .catch(reject)
  })
}

match
match(regExpression: RegExp, str: string): string[]
Curried version of String.prototype.match which returns empty array, when there is no match.
const result = [
  R.match('a', 'foo'),
  R.match(/([a-z]a)/g, 'bananas')
]
// => [[], ['ba', 'na', 'na']]
Try this R.match example in Rambda REPL
R.match source
export function match(pattern, input){
  if (arguments.length === 1) return _input => match(pattern, _input)
  const willReturn = input.match(pattern)
  return willReturn === null ? [] : willReturn
}

mathMod
R.mathMod behaves like the modulo operator should mathematically, unlike the % operator (and by extension, R.modulo). So while -17 % 5 is -2, mathMod(-17, 5) is 3.
:boom: Explanation is taken from
Ramdadocumentation site.
const result = [
  R.mathMod(-17, 5),
  R.mathMod(17, 5),
  R.mathMod(17, -5),  
  R.mathMod(17, 0)   
]
// => [3, 2, NaN, NaN]
Try this R.mathMod example in Rambda REPL

max
It returns the greater value between x and y.
const result = [
  R.max(5, 7),  
  R.max('bar', 'foo'),  
]
// => [7, 'foo']
Try this R.max example in Rambda REPL

maxBy
It returns the greater value between x and y according to compareFn function.
const compareFn = Math.abs
R.maxBy(compareFn, 5, -7) // => -7
Try this R.maxBy example in Rambda REPL

maybe
maybe<T>(ifRule: boolean, whenIf: T | Func<T>, whenElse: T | Func<T>): T
It acts as ternary operator and it is helpful when we have nested ternaries.
All of the inputs can be either direct values or anonymous functions. This is helpful if we don't want to evaluate certain paths as we can wrap this logic in a function.
const x = 4
const y = 8
const ifRule = x > 2
const whenIf = y > 10 ? 3 : 7
const whenElse = () => {
  // just to show that it won't be evaluated
  return JSON.parse('{a:')
}
const result = R.maybe(
  ifRule,
  whenIf,
  whenElse,
)
// `result` is `7`
Try this R.maybe example in Rambda REPL
R.maybe source
import { type } from './type.js'
export function maybe(
  ifRule, whenIf, whenElse
){
  const whenIfInput =
    ifRule && type(whenIf) === 'Function' ? whenIf() : whenIf
  const whenElseInput =
    !ifRule && type(whenElse) === 'Function' ? whenElse() : whenElse
  return ifRule ? whenIfInput : whenElseInput
}

mean
mean(list: number[]): number
It returns the mean value of list input.
R.mean([ 2, 7 ])
// => 4.5
Try this R.mean example in Rambda REPL
R.mean source
import { sum } from './sum.js'
export function mean(list){
  return sum(list) / list.length
}

median
median(list: number[]): number
It returns the median value of list input.
R.median([ 7, 2, 10, 9 ]) // => 8
Try this R.median example in Rambda REPL
R.median source
import { mean } from './mean.js'
export function median(list){
  const len = list.length
  if (len === 0) return NaN
  const width = 2 - len % 2
  const idx = (len - width) / 2
  return mean(Array.prototype.slice
    .call(list, 0)
    .sort((a, b) => {
      if (a === b) return 0
      return a < b ? -1 : 1
    })
    .slice(idx, idx + width))
}

memoize
memoize<T, K extends any[]>(fn: (...inputs: K) => T): (...inputs: K) => T
When fn is called for a second time with the same input, then the cache result is returned instead of calling again fn.
let result = 0
const fn = (a,b) =>{
  result++
  return a + b
}
const memoized = R.memoize(fn)
memoized(1, 2)
memoized(1, 2)
// => `result` is equal to `1`
Try this R.memoize example in Rambda REPL
R.memoize source
import { compose } from './compose.js'
import { map } from './map.js'
import { replace } from './replace.js'
import { sort } from './sort.js'
import { take } from './take.js'
import { type } from './type.js'
const cache = {}
const normalizeObject = obj => {
  const sortFn = (a, b) => a > b ? 1 : -1
  const willReturn = {}
  compose(map(prop => willReturn[ prop ] = obj[ prop ]),
    sort(sortFn))(Object.keys(obj))
  return willReturn
}
const stringify = a => {
  if (type(a) === 'String'){
    return a
  } else if ([ 'Function', 'Async' ].includes(type(a))){
    const compacted = replace(
      /\s{1,}/g, ' ', a.toString()
    )
    return replace(
      /\s/g, '_', take(15, compacted)
    )
  } else if (type(a) === 'Object'){
    return JSON.stringify(normalizeObject(a))
  }
  return JSON.stringify(a)
}
const generateProp = (fn, ...inputArguments) => {
  let propString = ''
  inputArguments.forEach(inputArgument => {
    propString += `${ stringify(inputArgument) }_`
  })
  return `${ propString }${ stringify(fn) }`
}
// with weakmaps
export function memoize(fn, ...inputArguments){
  if (arguments.length === 1){
    return (...inputArgumentsHolder) => memoize(fn, ...inputArgumentsHolder)
  }
  const prop = generateProp(fn, ...inputArguments)
  if (prop in cache) return cache[ prop ]
  if (type(fn) === 'Async'){
    return new Promise(resolve => {
      fn(...inputArguments).then(result => {
        cache[ prop ] = result
        resolve(result)
      })
    })
  }
  const result = fn(...inputArguments)
  cache[ prop ] = result
  return result
}

memoizeWith
memoizeWith<T, K extends any[]>(keyGen: any, fn: (...inputs: K) => T): (...inputs: K) => T
Creates a new function that, when invoked, caches the result of calling fn for a given argument set and returns the result.
const keyGen = (a,b) => a + b
let result = 0
const fn = (a,b) =>{
  result++
  return a + b
}
const memoized = R.memoizeWith(keyGen, fn)
memoized(1, 2)
memoized(1, 2)
// => `result` is equal to `1`
Try this R.memoizeWith example in Rambda REPL
R.memoizeWith source
export function memoizeWith(keyGen, fn){
  if (arguments.length === 1){
    return _fn => memoizeWith(keyGen, _fn)
  }
  const cache = new Map()
  return function (){
    const key = keyGen.apply(this, arguments)
    if (!cache.has(key)){
      cache.set(key, fn.apply(this, arguments))
    }
    return cache.get(key)
  }
}

merge
Same as R.mergeRight.

mergeAll
mergeAll<T>(list: object[]): T
It merges all objects of list array sequentially and returns the result.
const list = [
  {a: 1},
  {b: 2},
  {c: 3}
]
const result = R.mergeAll(list)
const expected = {
  a: 1,
  b: 2,
  c: 3
}
// => `result` is equal to `expected`
Try this R.mergeAll example in Rambda REPL
R.mergeAll source
import { map } from './map.js'
import { mergeRight } from './mergeRight.js'
export function mergeAll(arr){
  let willReturn = {}
  map(val => {
    willReturn = mergeRight(willReturn, val)
  }, arr)
  return willReturn
}

mergeDeepRight
mergeDeepRight<Output>(target: object, newProps: object): Output
Creates a new object with the own properties of the first object merged with the own properties of the second object. If a key exists in both objects:
- and both values are objects, the two values will be recursively merged
- otherwise the value from the second object will be used.
R.mergeDeepRight source
import { type } from './type.js'
export function mergeDeepRight(target, source){
  if (arguments.length === 1){
    return sourceHolder => mergeDeepRight(target, sourceHolder)
  }
  const willReturn = JSON.parse(JSON.stringify(target))
  Object.keys(source).forEach(key => {
    if (type(source[ key ]) === 'Object'){
      if (type(target[ key ]) === 'Object'){
        willReturn[ key ] = mergeDeepRight(target[ key ], source[ key ])
      } else {
        willReturn[ key ] = source[ key ]
      }
    } else {
      willReturn[ key ] = source[ key ]
    }
  })
  return willReturn
}

mergeLeft
mergeLeft<Output>(newProps: object, target: object): Output
Same as R.merge, but in opposite direction.
const result = R.mergeLeft(
  {a: 10},
  {a: 1, b: 2}
)
// => {a:10, b: 2}
Try this R.mergeLeft example in Rambda REPL
R.mergeLeft source
import { mergeRight } from './mergeRight.js'
export function mergeLeft(x, y){
  if (arguments.length === 1) return _y => mergeLeft(x, _y)
  return mergeRight(y, x)
}

mergeRight
It creates a copy of target object with overidden newProps properties. Previously known as R.merge but renamed after Ramda did the same.
const target = { 'foo': 0, 'bar': 1 }
const newProps = { 'foo': 7 }
const result = R.mergeRight(target, newProps)
// => { 'foo': 7, 'bar': 1 }
Try this R.mergeRight example in Rambda REPL

mergeWith
mergeWith(fn: (x: any, z: any) => any, a: Record<string, unknown>, b: Record<string, unknown>): Record<string, unknown>
It takes two objects and a function, which will be used when there is an overlap between the keys.
const result = R.mergeWith(
  R.concat,
  {values : [ 10, 20 ]},
  {values : [ 15, 35 ]}
)
// => [ 10, 20, 15, 35 ]
Try this R.mergeWith example in Rambda REPL
R.mergeWith source
import { curry } from './curry.js'
function mergeWithFn(
  mergeFn, a, b
){
  const willReturn = {}
  Object.keys(a).forEach(key => {
    if (b[ key ] === undefined){
      willReturn[ key ] = a[ key ]
    } else {
      willReturn[ key ] = mergeFn(a[ key ], b[ key ])
    }
  })
  Object.keys(b).forEach(key => {
    if (willReturn[ key ] !== undefined) return
    if (a[ key ] === undefined){
      willReturn[ key ] = b[ key ]
    } else {
      willReturn[ key ] = mergeFn(a[ key ], b[ key ])
    }
  })
  return willReturn
}
export const mergeWith = curry(mergeWithFn)

min
It returns the lesser value between x and y.
const result = [
  R.min(5, 7),  
  R.min('bar', 'foo'),  
]
// => [5, 'bar']
Try this R.min example in Rambda REPL

minBy
It returns the lesser value between x and y according to compareFn function.
const compareFn = Math.abs
R.minBy(compareFn, -5, 2) // => -5
Try this R.minBy example in Rambda REPL

modifyPath
modifyPath<T extends Record<string, unknown>>(path: Path, fn: (x: any) => unknown, object: Record<string, unknown>): T
It changes a property of object on the base of provided path and transformer function.
const result = R.modifyPath('a.b.c', x=> x+1, {a:{b: {c:1}}})
// => {a:{b: {c:2}}}
Try this R.modifyPath example in Rambda REPL
R.modifyPath source
import { _isArray } from './_internals/_isArray.js'
import { createPath } from './_internals/createPath.js'
import { assoc } from './assoc.js'
import { curry } from './curry.js'
import { path as pathModule } from './path.js'
export function modifyPathFn(
  pathInput, fn, object
){
  const path = createPath(pathInput)
  if (path.length === 1){
    return {
      ...object,
      [ path[0] ] : fn(object[ path[0] ]),
    }
  }
  if (pathModule(path, object) === undefined) return object
  const val = modifyPath(
    Array.prototype.slice.call(path, 1),
    fn,
    object[ path[ 0 ] ]
  )
  if (val === object[ path[ 0 ] ]){
    return object
  }
  return assoc(
    path[ 0 ], val, object
  )
}
export const modifyPath = curry(modifyPathFn)

modulo
Curried version of x%y.
R.modulo(17, 3) // => 2
Try this R.modulo example in Rambda REPL

move
It returns a copy of list with exchanged fromIndex and toIndex elements.
:boom: Rambda.move doesn't support negative indexes - it throws an error.
const list = [1, 2, 3]
const result = R.move(0, 1, list)
// => [2, 1, 3]
Try this R.move example in Rambda REPL

multiply
Curried version of x*y.
R.multiply(2, 4) // => 8
Try this R.multiply example in Rambda REPL

negate
R.negate(420)// => -420
Try this R.negate example in Rambda REPL

nextIndex
nextIndex(index: number, list: any[]): number
It returns the next index of the list.
If we have reached the end of the list, then it will return 0.
const list = [1, 2, 3]
const result = [
  R.nextIndex(0, list),
  R.nextIndex(1, list),
  R.nextIndex(2, list),
  R.nextIndex(10, list)
]
// => [1, 2, 0, 0]
Try this R.nextIndex example in Rambda REPL
R.nextIndex source
export function nextIndex(index, list){
  return index >= list.length - 1 ? 0 : index + 1
}

none
none<T>(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.
const list = [ 0, 1, 2, 3, 4 ]
const predicate = x => x > 6
const result = R.none(predicate, arr)
// => true
Try this R.none example in Rambda REPL
R.none source
export function none(predicate, list){
  if (arguments.length === 1) return _list => none(predicate, _list)
  for (let i = 0; i < list.length; i++){
    if (predicate(list[ i ])) return false
  }
  return true
}

not
not(input: any): boolean
It returns a boolean negated version of input.
R.not(false) // true
Try this R.not example in Rambda REPL
R.not source
export function not(input){
  return !input
}

nth
nth(index: number, input: string): string
Curried version of input[index].
const list = [1, 2, 3]
const str = 'foo'
const result = [
  R.nth(2, list),
  R.nth(6, list),
  R.nth(0, str),
]
// => [3, undefined, 'f']
Try this R.nth example in Rambda REPL
R.nth source
export function nth(index, input){
  if (arguments.length === 1) return _input => nth(index, _input)
  const idx = index < 0 ? input.length + index : index
  return Object.prototype.toString.call(input) === '[object String]' ?
    input.charAt(idx) :
    input[ idx ]
}

objOf
It creates an object with a single key-value pair.
const result = R.objOf('foo', 'bar')
// => {foo: 'bar'}
Try this R.objOf example in Rambda REPL

of
of<T>(x: T): T[]
R.of(null); // => [null]
R.of([42]); // => [[42]]
Try this R.of example in Rambda REPL
R.of source
export function of(value){
  return [ value ]
}

ok
ok(...inputs: any[]): (...schemas: any[]) => void | never
It checks if inputs are following schemas specifications according to R.isValid.
If validation fails, it throws.
:boom: It is same as
R.passbut instead of returningfalse, it throws an error.
const result = R.ok(
  1,
  ['foo', 'bar']
)(
  Number,
  [String]
)
// => undefined
Try this R.ok example in Rambda REPL
R.ok source
import { any } from './any.js'
import { glue } from './glue.js'
import { fromPrototypeToString, isValid } from './isValid.js'
import { map } from './map.js'
import { type } from './type.js'
export function schemaToString(schema){
  if (type(schema) !== 'Object'){
    return fromPrototypeToString(schema).rule
  }
  return map(x => {
    const { rule, parsed } = fromPrototypeToString(x)
    const xType = type(x)
    if (xType === 'Function' && !parsed) return 'Function'
    return parsed ? rule : xType
  }, schema)
}
export function check(singleInput, schema){
  return isValid({
    input  : { singleInput },
    schema : { singleInput : schema },
  })
}
export function ok(...inputs){
  return (...schemas) => {
    let failedSchema
    const anyError = any((singleInput, i) => {
      const schema = schemas[ i ] === undefined ? schemas[ 0 ] : schemas[ i ]
      const checked = check(singleInput, schema)
      if (!checked){
        failedSchema = JSON.stringify({
          input  : singleInput,
          schema : schemaToString(schema),
        })
      }
      return !checked
    }, inputs)
    if (anyError){
      const errorMessage =
        inputs.length > 1 ?
          glue(`
        Failed R.ok -
        reason: ${ failedSchema }
        all inputs: ${ JSON.stringify(inputs) }
        all schemas: ${ JSON.stringify(schemas.map(schemaToString)) }
      `,
          '\n') :
          `Failed R.ok - ${ failedSchema }`
      throw new Error(errorMessage)
    }
  }
}

omit
omit<T, K extends string>(propsToOmit: K[], obj: T): Omit<T, K>
It returns a partial copy of an obj without propsToOmit properties.
:boom: When using this method with
TypeScript, it is much easier to passpropsToOmitas an array. If passing a string, you will need to explicitly declare the output type.
const obj = {a: 1, b: 2, c: 3}
const propsToOmit = 'a,c,d'
const propsToOmitList = ['a', 'c', 'd']
const result = [
  R.omit(propsToOmit, Record<string, unknown>), 
  R.omit(propsToOmitList, Record<string, unknown>) 
]
// => [{b: 2}, {b: 2}]
Try this R.omit example in Rambda REPL
R.omit source
import { createPath } from './_internals/createPath.js'
export function omit(propsToOmit, obj){
  if (arguments.length === 1) return _obj => omit(propsToOmit, _obj)
  if (obj === null || obj === undefined){
    return undefined
  }
  const propsToOmitValue = createPath(propsToOmit, ',')
  const willReturn = {}
  for (const key in obj){
    if (!propsToOmitValue.includes(key)){
      willReturn[ key ] = obj[ key ]
    }
  }
  return willReturn
}

on
It passes the two inputs through unaryFn and then the results are passed as inputs the the binaryFn to receive the final result(binaryFn(unaryFn(FIRST_INPUT), unaryFn(SECOND_INPUT))).
This method is also known as P combinator.
const result = R.on((a, b) => a + b, R.prop('a'), {b:0, a:1}, {a:2})
// => 3
Try this R.on example in Rambda REPL

once
once<T extends AnyFunction>(func: T): T
It returns a function, which invokes only once fn function.
let result = 0
const addOnce = R.once((x) => result = result + x)
addOnce(1)
addOnce(1)
// => 1
Try this R.once example in Rambda REPL
R.once source
import { curry } from './curry.js'
function onceFn(fn, context){
  let result
  return function (){
    if (fn){
      result = fn.apply(context || this, arguments)
      fn = null
    }
    return result
  }
}
export function once(fn, context){
  if (arguments.length === 1){
    const wrap = onceFn(fn, context)
    return curry(wrap)
  }
  return onceFn(fn, context)
}

or
Logical OR
R.or(false, true); // => true
R.or(false, false); // => false
R.or(false, 'foo'); // => 'foo'
Try this R.or example in Rambda REPL

over
over<T>(lens: Lens, fn: Arity1Fn, value: T): T
It returns a copied Object or Array with modified value received by applying function fn to lens focus.
const headLens = R.lensIndex(0)
 
R.over(headLens, R.toUpper, ['foo', 'bar', 'baz']) // => ['FOO', 'bar', 'baz']
Try this R.over example in Rambda REPL
R.over source
import { curry } from './curry.js'
const Identity = x => ({
  x,
  map : fn => Identity(fn(x)),
})
function overFn(
  lens, fn, object
){
  return lens(x => Identity(fn(x)))(object).x
}
export const over = curry(overFn)

partial
partial<V0, V1, T>(fn: (x0: V0, x1: V1) => T, args: [V0]): (x1: V1) => T
It is very similar to R.curry, but you can pass initial arguments when you create the curried function.
R.partial will keep returning a function until all the arguments that the function fn expects are passed.
The name comes from the fact that you partially inject the inputs.
:boom: Rambda's partial doesn't need the input arguments to be wrapped as array.
const fn = (title, firstName, lastName) => {
  return title + ' ' + firstName + ' ' + lastName + '!'
}
const canPassAnyNumberOfArguments = R.partial(fn, 'Hello')
const ramdaStyle = R.partial(fn, ['Hello'])
const finalFn = canPassAnyNumberOfArguments('Foo')
finalFn('Bar') // =>  'Hello, Foo Bar!'
Try this R.partial example in Rambda REPL
R.partial source
export function partial(fn, ...args){
  const len = fn.length
  return (...rest) => {
    if (args.length + rest.length >= len){
      return fn(...args, ...rest)
    }
    return partial(fn, ...[ ...args, ...rest ])
  }
}

partialCurry
partialCurry<Input, PartialInput, Output>(
  fn: (input: Input) => Output, 
  partialInput: PartialInput,
): (input: Pick<Input, Exclude<keyof Input, keyof PartialInput>>) => Output
Same as R.partialObject.
When Ramda introduced R.partialObject, Rambdax already had such method, i.e. R.partialCurry. So this method is kept for backward compatibility.
:boom: Function input can be asynchronous
R.partialCurry source
export { partialObject as partialCurry } from './partialObject.js'

partialObject
partialObject<Input, PartialInput, Output>(
  fn: (input: Input) => Output, 
  partialInput: PartialInput,
): (input: Pick<Input, Exclude<keyof Input, keyof PartialInput>>) => Output
R.partialObject is a curry helper designed specifically for functions accepting object as a single argument.
Initially the function knows only a part from the whole input object and then R.partialObject helps in preparing the function for the second part, when it receives the rest of the input.
:boom: Function input can be asynchronous
const fn = ({ a, b, c }) => a + b + c
const curried = R.partialObject(fn, { a : 1 })
const result = curried({
  b : 2,
  c : 3,
})
// => 6
Try this R.partialObject example in Rambda REPL
R.partialObject source
import { mergeDeepRight } from './mergeDeepRight.js'
import { type } from './type.js'
export function partialObject(fn, input){
  return rest => {
    if (type(fn) === 'Async'){
      return new Promise((resolve, reject) => {
        fn(mergeDeepRight(rest, input)).then(resolve)
          .catch(reject)
      })
    }
    return fn(mergeDeepRight(rest, input))
  }
}

partition
partition<T>(
  predicate: Predicate<T>,
  input: T[]
): [T[], T[]]
It will return array of two objects/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.
const list = [1, 2, 3]
const obj = {a: 1, b: 2, c: 3}
const predicate = x => x > 2
const result = [
  R.partition(predicate, list),
  R.partition(predicate, Record<string, unknown>)
]
const expected = [
  [[3], [1, 2]],
  [{c: 3},  {a: 1, b: 2}],
]
// `result` is equal to `expected`
Try this R.partition example in Rambda REPL
R.partition source
import { _isArray } from './_internals/_isArray.js'
export function partitionObject(predicate, iterable){
  const yes = {}
  const no = {}
  Object.entries(iterable).forEach(([ prop, value ]) => {
    if (predicate(value, prop)){
      yes[ prop ] = value
    } else {
      no[ prop ] = value
    }
  })
  return [ yes, no ]
}
export function partitionArray(
  predicate, list, indexed = false
){
  const yes = []
  const no = []
  let counter = -1
  while (counter++ < list.length - 1){
    if (
      indexed ? predicate(list[ counter ], counter) : predicate(list[ counter ])
    ){
      yes.push(list[ counter ])
    } else {
      no.push(list[ counter ])
    }
  }
  return [ yes, no ]
}
export function partition(predicate, iterable){
  if (arguments.length === 1){
    return listHolder => partition(predicate, listHolder)
  }
  if (!_isArray(iterable)) return partitionObject(predicate, iterable)
  return partitionArray(predicate, iterable)
}

partitionIndexed

pass
pass(...inputs: any[]): (...rules: any[]) => boolean
It checks if inputs are following schemas specifications according to R.isValid.
const result = R.pass(
  1,
  ['foo','bar']
)(
  Number,
  [String]
)
// => true
Try this R.pass example in Rambda REPL
R.pass source
import { any } from './any.js'
import { check } from './ok.js'
export function pass(...inputs){
  return (...schemas) =>
    any((x, i) => {
      const schema = schemas[ i ] === undefined ? schemas[ 0 ] : schemas[ i ]
      return !check(x, schema)
    }, inputs) === false
}

path
path<Input, T>(pathToSearch: Path, obj: Input): T | undefined
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 anotation of
pathToSearchis one of the differences betweenRambdaandRamda.
const obj = {a: {b: 1}}
const pathToSearch = 'a.b'
const pathToSearchList = ['a', 'b']
const result = [
  R.path(pathToSearch, Record<string, unknown>),
  R.path(pathToSearchList, Record<string, unknown>),
  R.path('a.b.c.d', Record<string, unknown>)
]
// => [1, 1, undefined]
Try this R.path example in Rambda REPL
R.path source
import { createPath } from './_internals/createPath.js'
export function path(pathInput, obj){
  if (arguments.length === 1) return _obj => path(pathInput, _obj)
  if (obj === null || obj === undefined){
    return undefined
  }
  let willReturn = obj
  let counter = 0
  const 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
}

pathEq
pathEq(pathToSearch: Path, target: any, input: any): boolean
It returns true if pathToSearch of input object is equal to target value.
pathToSearch is passed to R.path, which means that it can be either a string or an array. Also equality between target and the found value is determined by R.equals.
const path = 'a.b'
const target = {c: 1}
const input = {a: {b: {c: 1}}}
const result = R.pathEq(
  path,
  target,
  input
)
// => true
Try this R.pathEq example in Rambda REPL
R.pathEq source
import { curry } from './curry.js'
import { equals } from './equals.js'
import { path } from './path.js'
function pathEqFn(
  pathToSearch, target, input
){
  return equals(path(pathToSearch, input), target)
}
export const pathEq = curry(pathEqFn)

pathOr
pathOr<T>(defaultValue: T, pathToSearch: Path, obj: any): T
It reads obj input and returns either R.path(pathToSearch, Record<string, unknown>) result or defaultValue input.
const defaultValue = 'DEFAULT_VALUE'
const pathToSearch = 'a.b'
const pathToSearchList = ['a', 'b']
const obj = {
  a : {
    b : 1
  }
}
const result = [
  R.pathOr(DEFAULT_VALUE, pathToSearch, Record<string, unknown>),
  R.pathOr(DEFAULT_VALUE, pathToSearchList, Record<string, unknown>), 
  R.pathOr(DEFAULT_VALUE, 'a.b.c', Record<string, unknown>)
]
// => [1, 1, 'DEFAULT_VALUE']
Try this R.pathOr example in Rambda REPL
R.pathOr source
import { curry } from './curry.js'
import { defaultTo } from './defaultTo.js'
import { path } from './path.js'
function pathOrFn(
  defaultValue, pathInput, obj
){
  return defaultTo(defaultValue, path(pathInput, obj))
}
export const pathOr = curry(pathOrFn)

paths
paths<Input, T>(pathsToSearch: Path[], obj: Input): (T | undefined)[]
It loops over members of pathsToSearch as singlePath and returns the array produced by R.path(singlePath, Record<string, unknown>).
Because it calls R.path, then singlePath can be either string or a list.
const obj = {
  a : {
    b : {
      c : 1,
      d : 2
    }
  }
}
const result = R.paths([
  'a.b.c',
  'a.b.d',
  'a.b.c.d.e',
], Record<string, unknown>)
// => [1, 2, undefined]
Try this R.paths example in Rambda REPL
R.paths source
import { path } from './path.js'
export function paths(pathsToSearch, obj){
  if (arguments.length === 1){
    return _obj => paths(pathsToSearch, _obj)
  }
  return pathsToSearch.map(singlePath => path(singlePath, obj))
}

pick
pick<T, K extends string | number | symbol>(propsToPick: K[], input: T): Pick<T, Exclude<keyof T, Exclude<keyof T, K>>>
It returns a partial copy of an input containing only propsToPick properties.
input can be either an object or an array.
String anotation of propsToPick is one of the differences between Rambda and Ramda.
:boom: When using this method with
TypeScript, it is much easier to passpropsToPickas an array. If passing a string, you will need to explicitly declare the output type.
const obj = {
  a : 1,
  b : false,
  foo: 'cherry'
}
const list = [1, 2, 3, 4]
const propsToPick = 'a,foo'
const propsToPickList = ['a', 'foo']
const result = [
  R.pick(propsToPick, Record<string, unknown>),
  R.pick(propsToPickList, Record<string, unknown>),
  R.pick('a,bar', Record<string, unknown>),
  R.pick('bar', Record<string, unknown>),
  R.pick([0, 3, 5], list),
  R.pick('0,3,5', list),
]
const expected = [
  {a:1, foo: 'cherry'},
  {a:1, foo: 'cherry'},
  {a:1},
  {},
  {0: 1, 3: 4},
  {0: 1, 3: 4},
]
// => `result` is equal to `expected`
Try this R.pick example in Rambda REPL
R.pick source
import { createPath } from './_internals/createPath.js'
export function pick(propsToPick, input){
  if (arguments.length === 1) return _input => pick(propsToPick, _input)
  if (input === null || input === undefined){
    return undefined
  }
  const keys = createPath(propsToPick, ',')
  const willReturn = {}
  let counter = 0
  while (counter < keys.length){
    if (keys[ counter ] in input){
      willReturn[ keys[ counter ] ] = input[ keys[ counter ] ]
    }
    counter++
  }
  return willReturn
}

pickAll
pickAll<T, U>(propsToPick: string[], input: T): U
Same as R.pick but it won't skip the missing props, i.e. it will assign them to undefined.
:boom: When using this method with
TypeScript, it is much easier to passpropsToPickas an array. If passing a string, you will need to explicitly declare the output type.
const obj = {
  a : 1,
  b : false,
  foo: 'cherry'
}
const propsToPick = 'a,foo,bar'
const propsToPickList = ['a', 'foo', 'bar']
const result = [
  R.pickAll(propsToPick, Record<string, unknown>),
  R.pickAll(propsToPickList, Record<string, unknown>),
  R.pickAll('a,bar', Record<string, unknown>),
  R.pickAll('bar', Record<string, unknown>),
]
const expected = [
  {a:1, foo: 'cherry', bar: undefined},
  {a:1, foo: 'cherry', bar: undefined},
  {a:1, bar: undefined},
  {bar: undefined}
]
// => `result` is equal to `expected`
Try this R.pickAll example in Rambda REPL
R.pickAll source
import { createPath } from './_internals/createPath.js'
export function pickAll(propsToPick, obj){
  if (arguments.length === 1) return _obj => pickAll(propsToPick, _obj)
  if (obj === null || obj === undefined){
    return undefined
  }
  const keysValue = createPath(propsToPick, ',')
  const willReturn = {}
  let counter = 0
  while (counter < keysValue.length){
    if (keysValue[ counter ] in obj){
      willReturn[ keysValue[ counter ] ] = obj[ keysValue[ counter ] ]
    } else {
      willReturn[ keysValue[ counter ] ] = undefined
    }
    counter++
  }
  return willReturn
}

pipe
It performs left-to-right function composition.
const result = R.pipe(
  R.filter(val => val > 2),
  R.map(a => a * 2)
)([1, 2, 3, 4])
// => [6, 8]
Try this R.pipe example in Rambda REPL

pipeAsync
pipeAsync<Out>(
  ...fns: (Async<any> | Func<any>)[]
): (input: any) => Promise<Out>
Asynchronous version of R.pipe
:boom: It doesn't work with promises or function returning promises such as
const foo = input => new Promise(...).
const add = async x => {
  await R.delay(100)
  return x + 1
}
const multiply = async x => {
  await R.delay(100)
  return x * 2 
}
const result = await R.pipeAsync(
  add,
  multiply
)(1)
// `result` resolves to `4`
Try this R.pipeAsync example in Rambda REPL
R.pipeAsync source
import { type } from './type.js'
export function pipeAsync(...inputArguments){
  return async function (startArgument){
    let argumentsToPass = startArgument
    while (inputArguments.length !== 0){
      const fn = inputArguments.shift()
      const typeFn = type(fn)
      if (typeFn === 'Async'){
        argumentsToPass = await fn(argumentsToPass)
      } else {
        argumentsToPass = fn(argumentsToPass)
        if (type(argumentsToPass) === 'Promise'){
          argumentsToPass = await argumentsToPass
        }
      }
    }
    return argumentsToPass
  }
}

piped
piped<A, B>(input: A, fn0: (x: A) => B) : B
It is basically R.pipe, but instead of passing input argument as R.pipe(...)(input), you pass it as the first argument.
const result = R.piped(
  [1, 2, 3],
  R.filter(x => x > 1),
  R.map(x => x*10),
)
// => [20, 30]
Try this R.piped example in Rambda REPL
R.piped source
import { pipe } from './pipe.js'
export function piped(...inputs){
  const [ input, ...fnList ] = inputs
  return pipe(...fnList)(input)
}

pipedAsync
pipedAsync<T>(
  input: any,
  ...fns: (Func<any> | Async<any>)[]
): Promise<T>
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.
:boom: Functions that return
Promisewill be handled as regular function not asynchronous. Such example isconst foo = input => new Promise(...).
const result = await R.pipedAsync(
  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.pipedAsync example in Rambda REPL
R.pipedAsync source
import { type } from './type.js'
export async function pipedAsync(...inputs){
  const [ input, ...fnList ] = inputs
  let argumentsToPass = input
  while (fnList.length !== 0){
    const fn = fnList.shift()
    const typeFn = type(fn)
    if (typeFn === 'Promise'){
      argumentsToPass = await fn(argumentsToPass)
    } else {
      argumentsToPass = fn(argumentsToPass)
    }
  }
  return argumentsToPass
}

pluck
pluck<K extends keyof T, T>(property: K, list: T[]): T[K][]
It returns list of the values of property taken from the all objects inside list.
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
R.pluck source
import { map } from './map.js'
export function pluck(property, list){
  if (arguments.length === 1) return _list => pluck(property, _list)
  const willReturn = []
  map(x => {
    if (x[ property ] !== undefined){
      willReturn.push(x[ property ])
    }
  }, list)
  return willReturn
}

prepend
prepend<T>(x: T, input: T[]): T[]
It adds element x at the beginning of list.
const result = R.prepend('foo', ['bar', 'baz'])
// => ['foo', 'bar', 'baz']
Try this R.prepend example in Rambda REPL
R.prepend source
export function prepend(x, input){
  if (arguments.length === 1) return _input => prepend(x, _input)
  if (typeof input === 'string') return [ x ].concat(input.split(''))
  return [ x ].concat(input)
}

prevIndex
prevIndex(index: number, list: any[]): number
It returns the next index of the list when the order is descending.
If we have reached the beginning of the list, then it will return the last index of the list.
:boom: Unlike
R.nextIndex, which safeguards against index out of bounds, this method does not.
const list = [1, 2, 3]
const result = [
  R.prevIndex(0, list),
  R.prevIndex(1, list),
  R.prevIndex(2, list),
]
// => [2, 0, 1]
Try this R.prevIndex example in Rambda REPL
R.prevIndex source
export function prevIndex(index, list){
  return index === 0 ? list.length - 1 : index - 1
}

produce
produce<Input extends any, Output>(
  rules: ProduceRules<Output, keyof Output, Input>,
  input: Input
): Output
It returns an object created by applying each value of rules to input argument.
:boom: In Typescript context,
rulesfunctions can be only 1 level deep. In Javascript context, there is no such restriction.
const rules = {
  foo: R.pipe(R.add(1), R.add(2)),
  a: {b: R.add(3)}
}
const result = R.produce(rules, 1)
const expected = {
  foo: 4,
  a: {b: 4}
}
// => `result` is equal to `expected`
Try this R.produce example in Rambda REPL
R.produce source
import { map } from './map.js'
import { type } from './type.js'
export function produce(rules, input){
  if (arguments.length === 1){
    return _input => produce(rules, _input)
  }
  return map(singleRule =>
    type(singleRule) === 'Object' ?
      produce(singleRule, input) :
      singleRule(input),
  rules)
}

produceAsync
produceAsync<Input extends any, Output>(
  rules: ProduceAsyncRules<Output, keyof Output, Input>,
  input: Input
): Promise<Output>
It returns an object created by applying each value of rules to input argument.
rules input is an object with synchronous or asynchronous functions as values.
The return value is wrapped in a promise, even if all rules are synchronous functions.
const rules = {
  foo: async x => {
    await R.delay(100)
    return x > 1
  },
  bar: x => ({baz: x})
}
const input = 2
const result = await R.produceAsync(rules, input)
const expected = {
  foo: true,
  bar: {baz: 2}
}
// => `result` is equal to `expected`
Try this R.produceAsync example in Rambda REPL
R.produceAsync source
import { map } from './map.js'
import { type } from './type.js'
function promisify({ condition, input, prop }){
  return new Promise((resolve, reject) => {
    if (type(condition) !== 'Promise'){
      return resolve({
        type    : prop,
        payload : condition(input),
      })
    }
    condition(input)
      .then(result => {
        resolve({
          type    : prop,
          payload : result,
        })
      })
      .catch(err => reject(err))
  })
}
function produceFn(conditions, input){
  let asyncConditionsFlag = false
  for (const prop in conditions){
    if (
      asyncConditionsFlag === false &&
      type(conditions[ prop ]) === 'Promise'
    ){
      asyncConditionsFlag = true
    }
  }
  if (asyncConditionsFlag === false){
    const willReturn = {}
    for (const prop in conditions){
      willReturn[ prop ] = conditions[ prop ](input)
    }
    return Promise.resolve(willReturn)
  }
  const promised = []
  for (const prop in conditions){
    const condition = conditions[ prop ]
    promised.push(promisify({
      input,
      condition,
      prop,
    }))
  }
  return new Promise((resolve, reject) => {
    Promise.all(promised)
      .then(results => {
        const willReturn = {}
        map(result => willReturn[ result.type ] = result.payload, results)
        resolve(willReturn)
      })
      .catch(err => reject(err))
  })
}
export function produceAsync(conditions, input){
  if (arguments.length === 1){
    return async _input => produceFn(conditions, _input)
  }
  return new Promise((resolve, reject) => {
    produceFn(conditions, input).then(resolve)
      .catch(reject)
  })
}

product
product(list: number[]): number
R.product([ 2, 3, 4 ])
// => 24)
Try this R.product example in Rambda REPL
R.product source
import { multiply } from './multiply.js'
import { reduce } from './reduce.js'
export const product = reduce(multiply, 1)

prop
prop<P extends keyof O, O>(propToFind: P, obj: O): O[P]
It returns the value of property propToFind in obj.
If there is no such property, it returns undefined.
const result = [
  R.prop('x', {x: 100}), 
  R.prop('x', {a: 1}) 
]
// => [100, undefined]
Try this R.prop example in Rambda REPL
R.prop source
export function prop(propToFind, obj){
  if (arguments.length === 1) return _obj => prop(propToFind, _obj)
  if (!obj) return undefined
  return obj[ propToFind ]
}

propEq
propEq<K extends string | number>(propToFind: K, valueToMatch: any, obj: Record<K, any>): boolean
It returns true if obj has property propToFind and its value is equal to valueToMatch.
const obj = { foo: 'bar' }
const secondObj = { foo: 1 }
const propToFind = 'foo'
const valueToMatch = 'bar'
const result = [
  R.propEq(propToFind, valueToMatch, Record<string, unknown>),
  R.propEq(propToFind, valueToMatch, secondRecord<string, unknown>)
]
// => [true, false]
Try this R.propEq example in Rambda REPL
R.propEq source
import { curry } from './curry.js'
import { equals } from './equals.js'
import { prop } from './prop.js'
function propEqFn(
  propToFind, valueToMatch, obj
){
  if (!obj) return false
  return equals(valueToMatch, prop(propToFind, obj))
}
export const propEq = curry(propEqFn)

propIs
propIs<C extends AnyFunction, K extends keyof any>(type: C, name: K, obj: any): obj is Record<K, ReturnType<C>>
It returns true if property of obj is from target type.
const obj = {a:1, b: 'foo'}
const result = [
  R.propIs(Number, 'a', Record<string, unknown>),
  R.propIs(String, 'b', Record<string, unknown>),
  R.propIs(Number, 'b', Record<string, unknown>),
]
// => [true, true, false]
Try this R.propIs example in Rambda REPL
R.propIs source
import { curry } from './curry.js'
import { is } from './is.js'
function propIsFn(
  targetPrototype, property, obj
){
  return is(targetPrototype, obj[ property ])
}
export const propIs = curry(propIsFn)

propOr
propOr<T, P extends string>(defaultValue: T, property: P, obj: Partial<Record<P, T>> | undefined): T
It returns either defaultValue or the value of property in obj.
const obj = {a: 1}
const defaultValue = 'DEFAULT_VALUE'
const property = 'a'
const result = [
  R.propOr(defaultValue, property, Record<string, unknown>),
  R.propOr(defaultValue, 'foo', Record<string, unknown>)
]
// => [1, 'DEFAULT_VALUE']
Try this R.propOr example in Rambda REPL
R.propOr source
import { curry } from './curry.js'
import { defaultTo } from './defaultTo.js'
function propOrFn(
  defaultValue, property, obj
){
  if (!obj) return defaultValue
  return defaultTo(defaultValue, obj[ property ])
}
export const propOr = curry(propOrFn)

props
props<P extends string, T>(propsToPick: P[], obj: Record<P, T>): T[]
It takes list with properties propsToPick and returns a list with property values in obj.
const result = R.props(
  ['a', 'b'], 
  {a:1, c:3}
)
// => [1, undefined]
Try this R.props example in Rambda REPL
R.props source
import { _isArray } from './_internals/_isArray.js'
import { mapArray } from './map.js'
export function props(propsToPick, obj){
  if (arguments.length === 1){
    return _obj => props(propsToPick, _obj)
  }
  if (!_isArray(propsToPick)){
    throw new Error('propsToPick is not a list')
  }
  return mapArray(prop => obj[ prop ], propsToPick)
}

propSatisfies
propSatisfies<T>(predicate: Predicate<T>, property: string, obj: Record<string, T>): boolean
It returns true if the object property satisfies a given predicate.
const obj = {a: {b:1}}
const property = 'a'
const predicate = x => x?.b === 1
const result = R.propSatisfies(predicate, property, Record<string, unknown>)
// => true
Try this R.propSatisfies example in Rambda REPL
R.propSatisfies source
import { curry } from './curry.js'
import { prop } from './prop.js'
function propSatisfiesFn(
  predicate, property, obj
){
  return predicate(prop(property, obj))
}
export const propSatisfies = curry(propSatisfiesFn)

random
random(minInclusive: number, maxInclusive: number): number
It returns a random number between min inclusive and max inclusive.
R.random source
export function random(min, max){
  return Math.floor(Math.random() * (max - min + 1)) + min
}

range
range(startInclusive: number, endExclusive: number): number[]
It returns list of numbers between startInclusive to endExclusive markers.
R.range(0, 5)
// => [0, 1, 2, 3, 4]
Try this R.range example in Rambda REPL
R.range source
export function range(start, end){
  if (arguments.length === 1) return _end => range(start, _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; i++){
    willReturn[ i ] = start + i
  }
  return willReturn
}

reduce
:boom: It passes index of the list as third argument to
reducerfunction.
const list = [1, 2, 3]
const initialValue = 10
const reducer = (prev, current) => prev * current
const result = R.reduce(reducer, initialValue, list)
// => 60
Try this R.reduce example in Rambda REPL

reject
reject<T>(predicate: Predicate<T>, list: T[]): T[]
It has the opposite effect of R.filter.
const list = [1, 2, 3, 4]
const obj = {a: 1, b: 2}
const predicate = x => x > 1
const result = [
  R.reject(predicate, list),
  R.reject(predicate, Record<string, unknown>)
]
// => [[1], {a: 1}]
Try this R.reject example in Rambda REPL
R.reject source
import { filter } from './filter.js'
export function reject(predicate, list){
  if (arguments.length === 1) return _list => reject(predicate, _list)
  return filter(x => !predicate(x), list)
}

rejectIndexed
Same as R.reject, but it passes index/property as second argument to the predicate, when looping over arrays/objects.
const list = [1, 2, 3, 4]
const obj = {a: 1, b: 2}
const result = [
  R.reject((x, index) => x > 1, list)
  R.reject((x, property) => x > 1, Record<string, unknown>)
]
// => [[1], {a: 1}]
Try this R.rejectIndexed example in Rambda REPL

remove
remove(
  toRemove: string | RegExp | (string | RegExp)[],
  text: string
): string
It will remove all toRemove entries from text sequentially.
toRemove argument can be either a list of strings/regular expressions or a single string/regular expression.
:boom: This is the only case where Rambdax exports clashes with Ramda API, as Ramda has
removemethod. IfRambda.removeis introduced, then this method will be renamed.
const result = R.remove(
  ['foo','bar'],
  'foo bar baz foo'
)
// => 'baz foo'
Try this R.remove example in Rambda REPL
R.remove source
import { replace } from './replace.js'
import { type } from './type.js'
export function remove(inputs, text){
  if (arguments.length === 1){
    return textHolder => remove(inputs, textHolder)
  }
  if (type(text) !== 'String'){
    throw new Error(`R.remove requires string not ${ type(text) }`)
  }
  if (type(inputs) !== 'Array'){
    return replace(
      inputs, '', text
    )
  }
  let textCopy = text
  inputs.forEach(singleInput => {
    textCopy = replace(
      singleInput, '', textCopy
    ).trim()
  })
  return textCopy
}

removeIndex
removeIndex<T>(index: number, list: T[]): T[]
It returns a copy of list input with removed index.
const list = [1, 2, 3, 4]
const result = R.removeIndex(1, list)
// => [1, 3, 4]
Try this R.removeIndex example in Rambda REPL
R.removeIndex source
export function removeIndex(index, list){
  if (arguments.length === 1) return _list => removeIndex(index, _list)
  if (index <= 0) return list.slice(1)
  if (index >= list.length - 1) return list.slice(0, list.length - 1)
  return [ ...list.slice(0, index), ...list.slice(index + 1) ]
}

renameProps
renameProps(rules: object, input: object): object
If property prop of rules is also a property in input, then rename input property to rules[prop].
R.renameProps source
import { mergeRight } from './mergeRight.js'
import { omit } from './omit.js'
export function renameProps(conditions, inputObject){
  if (arguments.length === 1){
    return inputObjectHolder => renameProps(conditions, inputObjectHolder)
  }
  const renamed = {}
  Object.keys(conditions).forEach(condition => {
    if (Object.keys(inputObject).includes(condition)){
      renamed[ conditions[ condition ] ] = inputObject[ condition ]
    }
  })
  return mergeRight(renamed, omit(Object.keys(conditions), inputObject))
}

repeat
repeat<T>(x: T): (timesToRepeat: number) => T[]
R.repeat('foo', 3)
// => ['foo', 'foo', 'foo']
Try this R.repeat example in Rambda REPL
R.repeat source
export function repeat(x, timesToRepeat){
  if (arguments.length === 1){
    return _timesToRepeat => repeat(x, _timesToRepeat)
  }
  return Array(timesToRepeat).fill(x)
}

replace
replace(strOrRegex: RegExp | string, replacer: string, str: string): string
It replaces strOrRegex found in str with replacer.
const strOrRegex = /o/g
const result = R.replace(strOrRegex, '|0|', 'foo')
// => 'f|0||0|'
Try this R.replace example in Rambda REPL
R.replace source
import { curry } from './curry.js'
function replaceFn(
  pattern, replacer, str
){
  return str.replace(pattern, replacer)
}
export const replace = curry(replaceFn)

replaceAll
replaceAll(patterns: (RegExp | string)[], replacer: string, input: string): string
Same as R.replace but it accepts array of string and regular expressions instead of a single value.
const replacer = '|'
const patterns = [ /foo/g, 'bar' ]
const input = 'foo bar baz foo bar'
const result = R.replaceAll(patterns, replacer, input)
// => '| | baz | bar'
Try this R.replaceAll example in Rambda REPL
R.replaceAll source
import { curry } from './curry.js'
import { ok } from './ok.js'
function replaceAllFn(
  patterns, replacer, input
){
  ok(
    patterns, replacer, input
  )(
    Array, String, String
  )
  let text = input
  patterns.forEach(singlePattern => {
    text = text.replace(singlePattern, replacer)
  })
  return text
}
export const replaceAll = curry(replaceAllFn)

reset
reset(): void
:boom:
R.gettermethod contains explanations, tests and source information ofR.reset,R.setterandR.gettermethods.

reverse
reverse<T>(input: T[]): T[]
It returns a reversed copy of list or string input.
const result = [
  R.reverse('foo'),
  R.reverse([1, 2, 3])
]
// => ['oof', [3, 2, 1]
Try this R.reverse example in Rambda REPL
R.reverse source
export function reverse(listOrString){
  if (typeof listOrString === 'string'){
    return listOrString.split('').reverse()
      .join('')
  }
  const clone = listOrString.slice()
  return clone.reverse()
}

set
set<T, U>(lens: Lens, replacer: U, obj: T): T
It returns a copied Object or Array with modified lens focus set to replacer value.
const input = {x: 1, y: 2}
const xLens = R.lensProp('x')
const result = [
  R.set(xLens, 4, input),
  R.set(xLens, 8, input) 
]
// => [{x: 4, y: 2}, {x: 8, y: 2}]
Try this R.set example in Rambda REPL
R.set source
import { always } from './always.js'
import { curry } from './curry.js'
import { over } from './over.js'
function setFn(
  lens, replacer, x
){
  return over(
    lens, always(replacer), x
  )
}
export const set = curry(setFn)

setter
setter(keyOrObject: string | object, value?: any): void
:boom:
R.gettermethod contains explanations, tests and source information ofR.reset,R.setterandR.gettermethods.

shuffle
shuffle<T>(list: T[]): T[]
It returns a randomized copy of array.
R.shuffle source
export function shuffle(arrayRaw){
  const array = arrayRaw.concat()
  let counter = array.length
  while (counter > 0){
    const index = Math.floor(Math.random() * counter)
    counter--
    const temp = array[ counter ]
    array[ counter ] = array[ index ]
    array[ index ] = temp
  }
  return array
}

slice
slice(from: number, to: number, input: string): string
const list = [0, 1, 2, 3, 4, 5]
const str = 'FOO_BAR'
const from = 1
const to = 4
const result = [
  R.slice(from, to, str),
  R.slice(from, to, list)
]
// => ['OO_', [1, 2, 3]]
Try this R.slice example in Rambda REPL
R.slice source
import { curry } from './curry.js'
function sliceFn(
  from, to, list
){
  return list.slice(from, to)
}
export const slice = curry(sliceFn)

sort
sort<T>(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.
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
R.sort source
import { cloneList } from './_internals/cloneList.js'
export function sort(sortFn, list){
  if (arguments.length === 1) return _list => sort(sortFn, _list)
  return cloneList(list).sort(sortFn)
}

sortBy
sortBy<T>(sortFn: (a: 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.
const list = [
  {a: 2},
  {a: 3},
  {a: 1}
]
const sortFn = x => x.a
const 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
R.sortBy source
import { cloneList } from './_internals/cloneList.js'
export function sortBy(sortFn, list){
  if (arguments.length === 1) return _list => sortBy(sortFn, _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
  })
}

sortByPath
sortByPath<T>(sortPath: Path, list: T[]): T[]
It returns copy of list sorted by sortPath value.
As sortPath is passed to R.path, it can be either a string or an array of strings.
const list = [
  {a: {b: 2}},
  {a: {b: 1}},
  {a: {b: 3}}
]
const result = R.sortByPath('a.b', list)
const expected = [
  {a: {b: 1}},
  {a: {b: 2}},
  {a: {b: 3}}
]
// => `result` is equal to `expected`
Try this R.sortByPath example in Rambda REPL
R.sortByPath source
import { path } from './path.js'
import { sortBy } from './sortBy.js'
export function sortByPath(sortPath, list){
  if (arguments.length === 1) return _list => sortByPath(sortPath, _list)
  return sortBy(path(sortPath), list)
}

sortByProps
sortByProps<T>(sortPaths: string[], list: T[]): T[]
It returns sorted copy of list of objects.
Sorting is done using a list of strings, each representing a path. Two members a and b from list can be sorted if both return a value for a given path. If the value is equal, then the next member of sortPaths(if there is such) will be used in order to find difference between a and b.
const list = [
  {a: {b: 2}},
  {a: {b: 1}},
  {a: {b: 3}}
]
const result = R.sortByProps(['a.b'], list)
const expected = [
  {a: {b: 1}},
  {a: {b: 2}},
  {a: {b: 3}}
]
// => `result` is equal to `expected`
Try this R.sortByProps example in Rambda REPL
R.sortByProps source
import { path } from './path.js'
function singleSort(
  a, b, sortPaths
){
  let toReturn = 0
  sortPaths.forEach(singlePath => {
    if (toReturn !== 0) return
    const aResult = path(singlePath, a)
    const bResult = path(singlePath, b)
    if ([ aResult, bResult ].includes(undefined)) return
    if (aResult === bResult) return
    toReturn = aResult > bResult ? 1 : -1
  })
  return toReturn
}
export function sortByProps(sortPaths, list){
  if (arguments.length === 1) return _list => sortByProps(sortPaths, _list)
  const clone = list.slice()
  clone.sort((a, b) => singleSort(
    a, b, sortPaths
  ))
  return clone
}

sortObject
sortObject<T>(predicate: SortObjectPredicate<T>, input: { [key: string]: T }): { [keyOutput: string]: T }
It returns a sorted version of input object.
const predicate = (propA, propB, valueA, valueB) => valueA > valueB ? -1 : 1
const result = R.sortObject(predicate, {a:1, b: 4, c: 2})
// => {b: 4, c: 2, a: 1}
Try this R.sortObject example in Rambda REPL
R.sortObject source
import { sort } from './sort.js'
export function sortObject(predicate, obj){
  if (arguments.length === 1){
    return _obj => sortObject(predicate, _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
}

split
split(separator: string | RegExp): (str: string) => string[]
Curried version of String.prototype.split
const str = 'foo|bar|baz'
const separator = '|'
const result = R.split(separator, str)
// => [ 'foo', 'bar', 'baz' ]
Try this R.split example in Rambda REPL
R.split source
export function split(separator, str){
  if (arguments.length === 1) return _str => split(separator, _str)
  return str.split(separator)
}

splitAt
splitAt<T>(index: number, input: T[]): [T[], T[]]
It splits string or array at a given index.
const list = [ 1, 2, 3 ]
const result = R.splitAt(2, list)
// => [[ 1, 2 ], [ 3 ]]
Try this R.splitAt example in Rambda REPL
R.splitAt source
import { _isArray } from './_internals/_isArray.js'
import { drop } from './drop.js'
import { maybe } from './maybe.js'
import { take } from './take.js'
export function splitAt(index, input){
  if (arguments.length === 1){
    return _list => splitAt(index, _list)
  }
  if (!input) throw new TypeError(`Cannot read property 'slice' of ${ input }`)
  if (!_isArray(input) && typeof input !== 'string') return [ [], [] ]
  const correctIndex = maybe(
    index < 0,
    input.length + index < 0 ? 0 : input.length + index,
    index
  )
  return [ take(correctIndex, input), drop(correctIndex, input) ]
}

splitEvery
splitEvery<T>(sliceLength: number, input: T[]): (T[])[]
It splits input into slices of sliceLength.
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
R.splitEvery source
export function splitEvery(sliceLength, listOrString){
  if (arguments.length === 1){
    return _listOrString => splitEvery(sliceLength, _listOrString)
  }
  if (sliceLength < 1){
    throw new Error('First argument to splitEvery must be a positive integer')
  }
  const willReturn = []
  let counter = 0
  while (counter < listOrString.length){
    willReturn.push(listOrString.slice(counter, counter += sliceLength))
  }
  return willReturn
}

splitWhen
splitWhen<T, U>(predicate: Predicate<T>, list: U[]): (U[])[]
It splits list to two arrays according to a predicate function.
The first array contains all members of list before predicate returns true.
const list = [1, 2, 1, 2]
const result = R.splitWhen(R.equals(2), list)
// => [[1], [2, 1, 2]]
Try this R.splitWhen example in Rambda REPL
R.splitWhen source
export function splitWhen(predicate, input){
  if (arguments.length === 1){
    return _input => splitWhen(predicate, _input)
  }
  if (!input)
    throw new TypeError(`Cannot read property 'length' of ${ input }`)
  const preFound = []
  const postFound = []
  let found = false
  let counter = -1
  while (counter++ < input.length - 1){
    if (found){
      postFound.push(input[ counter ])
    } else if (predicate(input[ counter ])){
      postFound.push(input[ counter ])
      found = true
    } else {
      preFound.push(input[ counter ])
    }
  }
  return [ preFound, postFound ]
}

startsWith
startsWith(target: string, str: string): boolean
When iterable is a string, then it behaves as String.prototype.startsWith.
When iterable is a list, then it uses R.equals to determine if the target list starts in the same way as the given target.
:boom: It doesn't work with arrays unlike its corresponding Ramda method.
const str = 'foo-bar'
const list = [{a:1}, {a:2}, {a:3}]
const result = [
  R.startsWith('foo', str),
  R.startsWith([{a:1}, {a:2}], list)
]
// => [true, true]
Try this R.startsWith example in Rambda REPL
R.startsWith source
import { _isArray } from './_internals/_isArray.js'
import { equals } from './equals.js'
export function startsWith(target, iterable){
  if (arguments.length === 1)
    return _iterable => startsWith(target, _iterable)
  if (typeof iterable === 'string'){
    return iterable.startsWith(target)
  }
  if (!_isArray(target)) return false
  let correct = true
  const filtered = target.filter((x, index) => {
    if (!correct) return false
    const result = equals(x, iterable[ index ])
    if (!result) correct = false
    return result
  })
  return filtered.length === target.length
}

subtract
Curried version of x - y
const x = 3
const y = 1
const result = R.subtract(x, y) 
// => 2
Try this R.subtract example in Rambda REPL

sum
sum(list: number[]): number
R.sum([1, 2, 3, 4, 5]) 
// => 15
Try this R.sum example in Rambda REPL
R.sum source
export function sum(list){
  return list.reduce((prev, current) => prev + current, 0)
}

switcher
switcher<T>(valueToMatch: any): Switchem<T>
Edited fork of Switchem library.
The method return a value if the matched option is a value.
If the matched option is a function, then R.switcher returns a function which expects input. Tests of the method explain it better than this short description.
R.equals is used to determine equality.
const valueToMatch = {foo: 1}
const result = R.switcher(valueToMatch)
  .is('baz', 'is baz')
  .is(x => typeof x === 'boolean', 'is boolean')
  .is({foo: 1}, 'Property foo is 1')
  .default('is bar')
// => 'Property foo is 1'
Try this R.switcher example in Rambda REPL
R.switcher source
import { equals } from './equals.js'
const NO_MATCH_FOUND = Symbol ? Symbol('NO_MATCH_FOUND') : undefined
const getMatchingKeyValuePair = (
  cases, testValue, defaultValue
) => {
  let iterationValue
  for (let index = 0; index < cases.length; index++){
    iterationValue = cases[ index ].test(testValue)
    if (iterationValue !== NO_MATCH_FOUND){
      return iterationValue
    }
  }
  return defaultValue
}
const isEqual = (testValue, matchValue) => {
  const willReturn =
    typeof testValue === 'function' ?
      testValue(matchValue) :
      equals(testValue, matchValue)
  return willReturn
}
const is = (testValue, matchResult = true) => ({
  key  : testValue,
  test : matchValue =>
    isEqual(testValue, matchValue) ? matchResult : NO_MATCH_FOUND,
})
class Switchem{
  constructor(
    defaultValue, cases, willMatch
  ){
    if (cases === undefined && willMatch === undefined){
      this.cases = []
      this.defaultValue = undefined
      this.willMatch = defaultValue
    } else {
      this.cases = cases
      this.defaultValue = defaultValue
      this.willMatch = willMatch
    }
    return this
  }
  default(defaultValue){
    const holder = new Switchem(
      defaultValue, this.cases, this.willMatch
    )
    return holder.match(this.willMatch)
  }
  is(testValue, matchResult){
    return new Switchem(
      this.defaultValue,
      [ ...this.cases, is(testValue, matchResult) ],
      this.willMatch
    )
  }
  match(matchValue){
    return getMatchingKeyValuePair(
      this.cases, matchValue, this.defaultValue
    )
  }
}
export function switcher(input){
  return new Switchem(input)
}

symmetricDifference
symmetricDifference<T>(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.
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
R.symmetricDifference source
import { concat } from './concat.js'
import { filter } from './filter.js'
import { includes } from './includes.js'
export function symmetricDifference(x, y){
  if (arguments.length === 1){
    return _y => symmetricDifference(x, _y)
  }
  return concat(filter(value => !includes(value, y), x),
    filter(value => !includes(value, x), y))
}

T
T(): boolean
R.T() 
// => true
Try this R.T example in Rambda REPL
R.T source
export function T(){
  return true
}

tail
tail<T extends unknown[]>(input: T): T extends [any, ...infer U] ? U : [...T]
It returns all but the first element of input.
const result = [
  R.tail([1, 2, 3]),  
  R.tail('foo') 
]
// => [[2, 3], 'oo']
Try this R.tail example in Rambda REPL
R.tail source
import { drop } from './drop.js'
export function tail(listOrString){
  return drop(1, listOrString)
}

take
take<T>(howMany: number, input: T[]): T[]
It returns the first howMany elements of input.
const howMany = 2
const result = [
  R.take(howMany, [1, 2, 3]),
  R.take(howMany, 'foobar'),
]
// => [[1, 2], 'fo']
Try this R.take example in Rambda REPL
R.take source
import baseSlice from './_internals/baseSlice.js'
export function take(howMany, listOrString){
  if (arguments.length === 1)
    return _listOrString => take(howMany, _listOrString)
  if (howMany < 0) return listOrString.slice()
  if (typeof listOrString === 'string') return listOrString.slice(0, howMany)
  return baseSlice(
    listOrString, 0, howMany
  )
}

takeLast
takeLast<T>(howMany: number, input: T[]): T[]
It returns the last howMany elements of input.
const howMany = 2
const result = [
  R.takeLast(howMany, [1, 2, 3]),
  R.takeLast(howMany, 'foobar'),
]
// => [[2, 3], 'ar']
Try this R.takeLast example in Rambda REPL
R.takeLast source
import baseSlice from './_internals/baseSlice.js'
export function takeLast(howMany, listOrString){
  if (arguments.length === 1)
    return _listOrString => takeLast(howMany, _listOrString)
  const len = listOrString.length
  if (howMany < 0) return listOrString.slice()
  let numValue = howMany > len ? len : howMany
  if (typeof listOrString === 'string')
    return listOrString.slice(len - numValue)
  numValue = len - numValue
  return baseSlice(
    listOrString, numValue, len
  )
}

takeLastWhile
takeLastWhile(predicate: (x: string) => boolean, input: string): string
const result = R.takeLastWhile(
  x => x > 2,
  [1, 2, 3, 4]
)
// => [3, 4]
Try this R.takeLastWhile example in Rambda REPL
R.takeLastWhile source
import { _isArray } from './_internals/_isArray.js'
export function takeLastWhile(predicate, input){
  if (arguments.length === 1){
    return _input => takeLastWhile(predicate, _input)
  }
  if (input.length === 0) return input
  let found = false
  const toReturn = []
  let counter = input.length
  while (!found || counter === 0){
    counter--
    if (predicate(input[ counter ]) === false){
      found = true
    } else if (!found){
      toReturn.push(input[ counter ])
    }
  }
  return _isArray(input) ? toReturn.reverse() : toReturn.reverse().join('')
}

takeUntil
takeUntil<T>(predicate: (x: T) => boolean, list: T[]): T[]
const list = [1, 2, 3, 4, 5]
const predicate = x => x > 3
const result = R.takeUntil(predicate, list)
// => [1, 2, 3]
Try this R.takeUntil example in Rambda REPL
R.takeUntil source
export function takeUntil(predicate, list){
  const toReturn = []
  let stopFlag = false
  let counter = -1
  while (stopFlag === false && counter++ < list.length - 1){
    if (predicate(list[ counter ])){
      stopFlag = true
    } else {
      toReturn.push(list[ counter ])
    }
  }
  return toReturn
}

takeWhile
const list = [1, 2, 3, 4]
const predicate = x => x < 3
const result = R.takeWhile(predicate, list)
// => [1, 2]
Try this R.takeWhile example in Rambda REPL

tap
tap<T>(fn: (x: T) => void, input: T): T
It applies function fn to input x and returns x.
One use case is debuging in the middle of R.compose.
const list = [1, 2, 3]
R.compose(
  R.map(x => x * 2)
  R.tap(console.log),
  R.filter(x => x > 1)
)(list)
// => `2` and `3` will be logged
Try this R.tap example in Rambda REPL
R.tap source
export function tap(fn, x){
  if (arguments.length === 1) return _x => tap(fn, _x)
  fn(x)
  return x
}

tapAsync
tapAsync<T>(fn: Func<any> | Promise<any>, input: T): T
Asynchronous version of R.tap.
R.tapAsync source
async function tapAsyncFn(fn, input){
  await fn(input)
  return input
}
export function tapAsync(fn, input){
  if (arguments.length === 1){
    return async _input => tapAsyncFn(fn, _input)
  }
  return new Promise((resolve, reject) => {
    tapAsyncFn(fn, input).then(resolve)
      .catch(reject)
  })
}

test
test(regExpression: RegExp): (str: string) => boolean
It determines whether str matches regExpression.
R.test(/^f/, 'foo')
// => true
Try this R.test example in Rambda REPL
R.test source
export function test(pattern, str){
  if (arguments.length === 1) return _str => test(pattern, _str)
  if (typeof pattern === 'string'){
    throw new TypeError(`‘test’ requires a value of type RegExp as its first argument; received "${ pattern }"`)
  }
  return str.search(pattern) !== -1
}

throttle
throttle<T, U>(fn: (input: T) => U, ms: number): (input: T) => U
let counter = 0
const inc = () => {
  counter++
}
const throttledInc = R.throttle(inc, 800)
const result = async () => {
  throttledInc()
  await R.delay(500)
  throttledInc()
  return counter
}
// `result` resolves to `1`
Try this R.throttle example in Rambda REPL
R.throttle source
export function throttle(fn, ms){
  let wait = false
  let result
  return function (...input){
    if (!wait){
      result = fn.apply(null, input)
      wait = true
      setTimeout(() => {
        wait = false
      }, ms)
    }
    return result
  }
}

times
times<T>(fn: (i: number) => T, howMany: number): T[]
It returns the result of applying function fn over members of range array.
The range array includes numbers between 0 and howMany(exclusive).
const fn = x => x * 2
const howMany = 5
R.times(fn, howMany)
// => [0, 2, 4, 6, 8]
Try this R.times example in Rambda REPL
R.times source
import { map } from './map.js'
import { range } from './range.js'
export function times(fn, howMany){
  if (arguments.length === 1) return _howMany => times(fn, _howMany)
  if (!Number.isInteger(howMany) || howMany < 0){
    throw new RangeError('n must be an integer')
  }
  return map(fn, range(0, howMany))
}

toDecimal
toDecimal(num: number, charsAfterDecimalPoint?: number): number
R.toDecimal(2.45464,2) // => 2.45
Try this R.toDecimal example in Rambda REPL
R.toDecimal source
export function toDecimal(number, charsAfterDecimalPoint = 2){
  return Number(parseFloat(String(number)).toFixed(charsAfterDecimalPoint))
}

toLower
toLower<S extends string>(str: S): Lowercase<S>
R.toLower('FOO')
// => 'foo'
Try this R.toLower example in Rambda REPL
R.toLower source
export function toLower(str){
  return str.toLowerCase()
}

toPairs
toPairs<O extends object, K extends Extract<keyof O, string | number>>(obj: O): Array<{ [key in K]: [`${key}`, O[key]] }[K]>
It transforms an object to a list.
const list = {
  a : 1,
  b : 2,
  c : [ 3, 4 ],
}
const expected = [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', [ 3, 4 ] ] ]
const result = R.toPairs(list)
// => `result` is equal to `expected`
Try this R.toPairs example in Rambda REPL
R.toPairs source
export function toPairs(obj){
  return Object.entries(obj)
}

toString
toString(x: unknown): string
R.toString([1, 2]) 
// => '1,2'
Try this R.toString example in Rambda REPL
R.toString source
export function toString(x){
  return x.toString()
}

toUpper
toUpper<S extends string>(str: S): Uppercase<S>
R.toUpper('foo')
// => 'FOO'
Try this R.toUpper example in Rambda REPL
R.toUpper source
export function toUpper(str){
  return str.toUpperCase()
}

transpose
transpose<T>(list: (T[])[]): (T[])[]
const list = [[10, 11], [20], [], [30, 31, 32]]
const expected = [[10, 20, 30], [11, 31], [32]]
const result = R.transpose(list)
// => `result` is equal to `expected`
Try this R.transpose example in Rambda REPL
R.transpose source
import { _isArray } from './_internals/_isArray.js'
export function transpose(array){
  return array.reduce((acc, el) => {
    el.forEach((nestedEl, i) =>
      _isArray(acc[ i ]) ? acc[ i ].push(nestedEl) : acc.push([ nestedEl ]))
    return acc
  }, [])
}

trim
trim(str: string): string
R.trim('  foo  ') 
// => 'foo'
Try this R.trim example in Rambda REPL
R.trim source
export function trim(str){
  return str.trim()
}

tryCatch
It returns function that runs fn in try/catch block. If there was an error, then fallback is used to return the result. Note that fn can be value or asynchronous/synchronous function(unlike Ramda where fallback can only be a synchronous function).
:boom: Please check the tests of
R.tryCatchto fully understand how this method works.
const fn = x => x.foo
const result = [
  R.tryCatch(fn, false)(null),
  R.tryCatch(fn, false)({foo: 'bar'})
]
// => [false, 'bar']
Try this R.tryCatch example in Rambda REPL

tryCatchAsync
tryCatchAsync<T>(
  fn: (input: any) => Promise<T>,
  fallback: T
): (input: any) => Promise<T>
It returns function that runs fn in try/catch block. If there was an error, then fallback is used to return the result.
const x = {foo: 1}
const fnFoo = async () => x.foo
const fnBar = async () => x.bar
const result = await Promise.all([
  R.tryCatchAsync (fnFoo, false)(),
  R.tryCatchAsync(fnBar, false)()
])
// => [1, false]
Try this R.tryCatchAsync example in Rambda REPL
R.tryCatchAsync source
import { type } from './type.js'
export function tryCatchAsync(fn, fallback){
  return (...inputs) =>
    new Promise(resolve => {
      fn(...inputs)
        .then(resolve)
        .catch(err => {
          if (type(fallback) !== 'Function'){
            return resolve(fallback)
          }
          if (type(fallback) !== 'Promise'){
            return resolve(fallback(err, ...inputs))
          }
          fallback(err, ...inputs)
            .then(resolve)
            .catch(resolve)
        })
    })
}

type
It accepts any input and it returns its type.
:boom:
NaN,PromiseandAsyncare types specific for Rambda.
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

unapply
unapply<T = any>(fn: (args: any[]) => T): (...args: any[]) => T
It calls a function fn with the list of values of the returned function.
R.unapply is the opposite of R.apply method.
R.unapply(JSON.stringify)(1, 2, 3)
//=> '[1,2,3]'
Try this R.unapply example in Rambda REPL
R.unapply source
export function unapply(fn){
  return function (...args){
    return fn.call(this, args)
  }
}

union
union<T>(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.
const result = R.union([1,2,3], [3,4,5]);
// => [1, 2, 3, 4, 5]
Try this R.union example in Rambda REPL
R.union source
import { cloneList } from './_internals/cloneList.js'
import { includes } from './includes.js'
export function union(x, y){
  if (arguments.length === 1) return _y => union(x, _y)
  const toReturn = cloneList(x)
  y.forEach(yInstance => {
    if (!includes(yInstance, x)) toReturn.push(yInstance)
  })
  return toReturn
}

uniq
uniq<T>(list: T[]): T[]
It returns a new array containing only one copy of each element of list.
R.equals is used to determine equality.
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
R.uniq source
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
}

uniqBy
const result = R.uniqBy(Math.abs, [ -2, 1, 0, -1, 2 ])
// => [-2, 1, 0]
Try this R.uniqBy example in Rambda REPL

uniqWith
uniqWith<T, U>(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.
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
R.uniqWith source
function includesWith(
  predicate, target, list
){
  let willReturn = false
  let index = -1
  while (++index < list.length && !willReturn){
    const value = list[ index ]
    if (predicate(target, value)){
      willReturn = true
    }
  }
  return willReturn
}
export function uniqWith(predicate, list){
  if (arguments.length === 1) return _list => uniqWith(predicate, _list)
  let index = -1
  const willReturn = []
  while (++index < list.length){
    const value = list[ index ]
    if (!includesWith(
      predicate, value, willReturn
    )){
      willReturn.push(value)
    }
  }
  return willReturn
}

unless
unless<T, U>(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.
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
R.unless source
export function unless(predicate, whenFalse){
  if (arguments.length === 1){
    return _whenFalse => unless(predicate, _whenFalse)
  }
  return input => predicate(input) ? input : whenFalse(input)
}

unwind
const obj = {
  a: 1,
  b: [2, 3],
}
const result = unwind('b', Record<string, unknown>)
const expected = [{a:1, b:2}, {a:1, b:3}]
// => `result` is equal to `expected`
Try this R.unwind example in Rambda REPL

update
update<T>(index: number, newValue: T, list: T[]): T[]
It returns a copy of list with updated element at index with newValue.
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
R.update source
import { cloneList } from './_internals/cloneList.js'
import { curry } from './curry.js'
function updateFn(
  index, newValue, list
){
  const clone = cloneList(list)
  if (index === -1) return clone.fill(newValue, index)
  return clone.fill(
    newValue, index, index + 1
  )
}
export const update = curry(updateFn)

updateObject
updateObject<Output>(rules: ([string, any])[], input: object): Output
Very similar to R.assocPath but it applies list of updates instead of only a single update.
It returns a copy of obj input with changed properties according to rules input.
Each instance of rules is a tuple of object path and the new value for this path. If such object path does not exist, then such object path is created.
As it uses R.path underneath, object path can be either string or array of strings(in Typescript object path can be only a string).
const obj = {
  a: {b: 1},
  foo: {bar: 10},
}
const rules = [
  ['a.b', 2],
  ['foo.bar', 20],
  ['q.z', 300],
]
const result = R.updateObject(rules, Record<string, unknown>)
const expected = {
  a: {b: 2},
  foo: {bar: 20},
  q: {z: 300},
}
// => `result` is equal to `expected`
Try this R.updateObject example in Rambda REPL
R.updateObject source
import { assocPath } from './assocPath.js'
export function updateObject(rules, obj){
  if (arguments.length === 1) return _obj => updateObject(rules, _obj)
  let clone = { ...obj } /*?.*/
  rules.forEach(([ objectPath, newValue ]) => {
    clone = assocPath(
      objectPath, newValue, clone
    )
  })
  return clone
}

values
values<T extends object, K extends keyof T>(obj: T): T[K][]
With correct input, this is nothing more than Object.values(Record<string, unknown>). If obj is not an object, then it returns an empty array.
const obj = {a:1, b:2}
R.values(Record<string, unknown>)
// => [1, 2]
Try this R.values example in Rambda REPL
R.values source
import { type } from './type.js'
export function values(obj){
  if (type(obj) !== 'Object') return []
  return Object.values(obj)
}

view
view<T, U>(lens: Lens): (target: T) => U
It returns the value of lens focus over target object.
const lens = R.lensProp('x')
R.view(lens, {x: 1, y: 2}) // => 1
R.view(lens, {x: 4, y: 2}) // => 4
Try this R.view example in Rambda REPL
R.view source
const Const = x => ({
  x,
  map : fn => Const(x),
})
export function view(lens, target){
  if (arguments.length === 1) return _target => view(lens, _target)
  return lens(Const)(target).x
}

viewOr
viewOr<Input, Output>(fallback: Output, lens: Lens, input: Input): Output
A combination between R.defaultTo and `R.view.
const lens = R.lensProp('a');
const input = {a: 'foo'}
const fallbackInput = {b: 'bar'}
const fallback = 'FALLBACK'
const result = [
  R.viewOr(fallback, lens, input),
  R.viewOr(fallback, lens, fallbackInput)
]
// => ['foo', 'FALLBACK']
Try this R.viewOr example in Rambda REPL
R.viewOr source
import { curry } from './curry.js'
import { defaultTo } from './defaultTo.js'
import { view } from './view.js'
function viewOrFn(
  fallback, lens, input
){
  return defaultTo(fallback, view(lens, input))
}
export const viewOr = curry(viewOrFn)

wait
wait<T>(fn: Promise<T>): Promise<[T, Error|undefined]>
It provides Golang-like interface for handling promises.
const [result, err] = await R.wait(R.delay(1000))
// => err is undefined
// => result is `RAMBDAX_DELAY`
Try this R.wait example in Rambda REPL
R.wait source
export function wait(fn){
  return new Promise(resolve => {
    fn.then(result => resolve([ result, undefined ])).catch(e =>
      resolve([ undefined, e ]))
  })
}

waitFor
waitFor(
  waitForTrueCondition: () => boolean,
  howLong: number,
  loops?: number
): () => Promise<boolean>
It returns true, if condition returns true within howLong milisececonds time period.
The method accepts an optional third argument loops(default to 10), which is the number of times waitForTrueCondition will be evaluated for howLong period. Once this function returns a value different from false, this value will be the final result.
Otherwise, R.waitFor will return false.
const howLong = 1000
let counter = 0
const waitForTrueCondition = async x => {
  await R.delay(100)
  counter = counter + x
  return counter > 10
}
const result = await R.waitFor(waitForTrueCondition, howLong)(2)
// => true
Try this R.waitFor example in Rambda REPL
R.waitFor source
import { delay } from './delay.js'
import { range } from './range.js'
import { type } from './type.js'
export function waitFor(
  condition, howLong, loops = 10
){
  const typeCondition = type(condition)
  const passPromise = typeCondition === 'Promise'
  const passFunction = typeCondition === 'Function'
  const interval = Math.floor(howLong / loops)
  if (!(passPromise || passFunction)){
    throw new Error('R.waitFor')
  }
  return async (...inputs) => {
    for (const _ of range(0, loops)){
      const resultCondition = await condition(...inputs)
      if (resultCondition === false){
        await delay(interval)
      } else {
        return resultCondition
      }
    }
    return false
  }
}

when
when<T, U>(predicate: (x: T) => boolean, whenTrueFn: (a: T) => U, input: T): T | U
R.when source
import { curry } from './curry.js'
function whenFn(
  predicate, whenTrueFn, input
){
  if (!predicate(input)) return input
  return whenTrueFn(input)
}
export const when = curry(whenFn)

where
where<T, U>(conditions: T, input: U): boolean
It returns true if all each property in conditions returns true when applied to corresponding property in input object.
const condition = R.where({
  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.where example in Rambda REPL
R.where source
export function where(conditions, input){
  if (input === undefined){
    return _input => where(conditions, _input)
  }
  let flag = true
  for (const prop in conditions){
    const result = conditions[ prop ](input[ prop ])
    if (flag && result === false){
      flag = false
    }
  }
  return flag
}

whereAny
Same as R.where, but it will return true if at least one condition check returns true.
const conditions = {
  a: a => a > 1,
  b: b => b > 2,
}
const result = [
  R.whereAny(conditions, {b:3}),
  R.whereAny(conditions, {c:4})
]
// => [true, false]
Try this R.whereAny example in Rambda REPL

whereEq
whereEq<T, U>(condition: T, input: U): boolean
It will return true if all of input object fully or partially include rule object.
R.equals is used to determine equality.
const condition = { a : { b : 1 } }
const input = {
  a : { b : 1 },
  c : 2
}
const result = whereEq(condition, input)
// => true
Try this R.whereEq example in Rambda REPL
R.whereEq source
import { equals } from './equals.js'
import { filter } from './filter.js'
export function whereEq(condition, input){
  if (arguments.length === 1){
    return _input => whereEq(condition, _input)
  }
  const result = filter((conditionValue, conditionProp) =>
    equals(conditionValue, input[ conditionProp ]),
  condition)
  return Object.keys(result).length === Object.keys(condition).length
}

without
without<T>(matchAgainst: T[], source: T[]): T[]
It will return a new array, based on all members of source list that are not part of matchAgainst list.
R.equals is used to determine equality.
const source = [1, 2, 3, 4]
const matchAgainst = [2, 3]
const result = R.without(matchAgainst, source)
// => [1, 4]
Try this R.without example in Rambda REPL
R.without source
import { _indexOf } from './equals.js'
import { reduce } from './reduce.js'
export function without(matchAgainst, source){
  if (source === undefined){
    return _source => without(matchAgainst, _source)
  }
  return reduce(
    (prev, current) =>
      _indexOf(current, matchAgainst) > -1 ? prev : prev.concat(current),
    [],
    source
  )
}

xnor
xnor(x: boolean, y: boolean): boolean
Logical XNOR
const result = [
  R.xnor(1, 0),
  R.xnor(0, 1),
  R.xnor(0, 0),
  R.xnor(1, 1),
]
// => [true, false, false, true]
Try this R.xnor example in Rambda REPL
R.xnor source
export function xnor(x, y){
  if (arguments.length === 1){
    return _y => xnor(x, _y)
  }
  return Boolean(x && y || !x && !y)
}

xor
xor(x: boolean, y: boolean): boolean
Logical XOR
const result = [
  xor(true, true),
  xor(false, false),
  xor(false, true),
]
// => [false, false, true]
Try this R.xor example in Rambda REPL
R.xor source
export function xor(a, b){
  if (arguments.length === 1) return _b => xor(a, _b)
  return Boolean(a) && !b || Boolean(b) && !a
}

zip
zip<K, V>(x: K[], y: V[]): KeyValuePair<K, V>[]
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.
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
R.zip source
export function zip(left, right){
  if (arguments.length === 1) return _right => zip(left, _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
}

zipObj
zipObj<T, K extends string>(keys: K[], values: T[]): { [P in K]: T }
It will return a new object with keys of keys array and values of values array.
const keys = ['a', 'b', 'c']
R.zipObj(keys, [1, 2, 3])
// => {a: 1, b: 2, c: 3}
// truncates to shortest list
R.zipObj(keys, [1, 2])
// => {a: 1, b: 2}
Try this R.zipObj example in Rambda REPL
R.zipObj source
import { take } from './take.js'
export function zipObj(keys, values){
  if (arguments.length === 1) return yHolder => zipObj(keys, yHolder)
  return take(values.length, keys).reduce((
    prev, xInstance, i
  ) => {
    prev[ xInstance ] = values[ i ]
    return prev
  }, {})
}

zipWith
zipWith<T, U, TResult>(fn: (x: T, y: U) => TResult, list1: T[], list2: U[]): TResult[]
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
R.zipWith source
import { curry } from './curry.js'
import { take } from './take.js'
function zipWithFn(
  fn, x, y
){
  return take(x.length > y.length ? y.length : x.length, x).map((xInstance, i) => fn(xInstance, y[ i ]))
}
export const zipWith = curry(zipWithFn)

❯ CHANGELOG
8.1.0
- 
Breaking change due to renaming of R.partialCurrytoR.partialObject.
- 
Wrong R.updateif index is-1- PR #593
- 
Wrong curried typings in R.anyPass- Issue #642
- 
R.modifyPathnot exported - Issue #640
- 
Add new method R.uniqBy. Implementation is coming from Ramda MR#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
- 
Rambda's pipe/composedoesn't return proper length of composed function which leads to issue withR.applySpec. It was fixed by alligning Rambda'spipe/composewith Ramda logic - Issue #627
- 
Replace AsyncwithPromiseas return type ofR.type.
- 
Add new types as Typescript output for R.type- "Map", "WeakMap", "Generator", "GeneratorFunction", "BigInt", "ArrayBuffer"
- 
Add new methods after Ramdaversion upgrade to0.28.0:
-- R.count -- R.modifyPath -- R.on -- R.whereAny
- 
Replace AsyncwithPromiseas return type ofR.type.
- 
Remove isFunctionmethod
- 
Add R.juxtmethod
- 
Add R.containsmethod
- 
Add R.mapcatmethod WIP
- 
Add R.flattenObjectmethod
- 
Add R.deletePathmethod WIP
- 
Change R.countlogic to match the newRamda.countmethod. Instead of counting for target value, the counting is done by predicate function.
8.0.1
- Rambdax doesn't work with pnpmdue to wrong export configuration - Issue #619
8.0.0
- Breaking change - sync R.compose/R.pipewith@types/ramda. That is significant change so as safeguard, it will lead a major bump. Important - this lead to raising required Typescript version to4.2.2. In other words, to useRambdayou'll need Typescript version4.2.2or 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. 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.jsonbased on this blog post and this merged Ramda's PR. This also led to renaming ofbabel.config.jstobabel.config.cjs.
- 
Add R.apply,R.bindandR.unapply
- 
Fix missing return value in R.throttle- Issue #76
- 
Add R.findAsync- Issue #65
- 
Fix R.debouncetypings as the method actually doesn't return a result.
- 
R.startsWith/R.endsWithnow support lists as inputs. This way, it matches current Ramda behavior.
- 
Remove unused typing for R.chain.
- 
R.map/R.filterno longer accept bad inputs as iterable. This way, Rambda behaves more like Ramda, which also throws.
- 
Make R.lastIndexOffollow the logic ofR.indexOf.
- 
Change R.typelogic to Ramda logic. This way,R.typecan returnErrorandSetas results.
- 
Add missing logic in R.equalsto compare sets - Issue #599
- 
Improve list cloning - Issue #595 
- 
Handle multiple inputs with R.allPassandR.anyPass- Issue #604
- 
Fix R.lengthwrong logic with inputs as{length: 123}- Issue #606.
- 
Improve non-curry typings of R.mergeby using types from mobily/ts-belt.
- 
Improve performance of R.uniqWith.
- 
Wrong R.updateif index is-1- PR #593
- 
Make R.eqPropssafe for falsy inputs - based on this opened Ramda PR.
- 
Incorrect benchmarks for R.pipe/R.compose- Issue #608
- 
Fix R.last/R.headtypings - Issue #609
7.4.1
- 
Fix corrupted Typescript definitions - Rambdax issue #72 
- 
Fix slow R.uniqmethods - Issue #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
7.4.0
- 
Add R.objOfmethod
- 
Add R.mapObjIndexedmethod
7.3.0
- 
Add R.rejectIndexedandR.partitionIndexedmethods - Rambdax issue #67
- 
Expose R.mapObject,R.mapArray,R.filterObjectandR.filterArray- Issue #578
- 
R.hasuseObject.prototype.hasOwnProperty- Issue #572
- 
Fix R.intersectionwrong order compared to Ramda.
- 
Expose immutable.tstypings which are Rambda typings withreadonlystatements - Issue #565, Rambdax issue #69
- 
R.pathwrong return ofnullinstead ofundefinedwhen path value isnull- PR #577
- 
Wrong arguments order in R.removeIndex- Issue #66
- 
Change R.pipedtypings to mimic that ofR.pipe. Main difference is thatR.pipeis focused on unary functions.
- 
Fix wrong logic when R.withoutuseR.includeswhile it should use array version ofR.includes.
- 
Use uglify plugin for UMD bundle. 
- 
Remove ts-toolbelttypes from Typescript definitions. Most affected are the following methods, which lose one of its curried definitions:
- R.maxBy
- R.minBy
- R.pathEq
- R.viewOr
- R.when
- R.merge
- R.mergeDeepRight
- R.mergeLeft
7.2.0
- 
Approve PR #61 - fix wrong R.isValidtypings
- 
R.produceAsync returns promise even if all rules are synchronous. 
- 
R.defaultTono longer accepts infinite inputs, thus it follows Ramda implementation.
- 
R.equalssupports equality of functions.
- 
R.pipedoesn't useR.compose.
- 
Close Issue #561 - export several internal TS interfaces and types 
- 
Add CHANGELOG.mdfile in release files list
7.1.0
- 
Add R.tryCatchAsync
- 
Add R.xnor
- 
R.equalssupports equality of functions.
- 
Close Issue #559 - improve R.propOrtypings
- 
Close Issue #560 - apply immutable lint to Typescript definitions 
- 
Close Issue #553 - fix problem with curried typings of R.prop
- 
Fix wrong R.lasttyping
- 
Upgrade all rolluprelated dependencies
- 
R.typesupportsSymboljust like Ramda.
- 
Remove file extension in mainproperty inpackage.jsonin order to allowexperimental-modules. See also this Ramda's PR - https://github.com/ramda/ramda/pull/2678/files
- 
Import R.indexBy/R.when/R.zipObj/R.propEq/R.complementchanges from recent@types/ramdarelease.
- 
R.tryCatchstop supporting asynchronous functions; the previous behaviour is exported to Rambdax asR.tryCatchAsync
7.0.1
- Fix missing Evolveddeclaration in Typescript definition
7.0.0
- 
Rename R.producetoR.produceAsync
- 
Add R.producewhich is synchronous version ofR.produceAsync
- 
Stop supporting expression inside template's props. Also, spaces are no longer allowed between {{and}}, i.e.R.interpolate('{{ foo }}', x)should beR.interpolate('{{foo}}', x).
- 
Add typings for R.takeWhilewhen iterable is a string
- 
Add R.takeLastWhile
- 
Add R.dropWhile
- 
Add R.eqProps
- 
Add R.dropLastWhile
- 
Add R.dropRepeats
- 
Add R.dropRepeatsWith
- 
Add R.evolve
6.2.0
- 
R.switcheracceptsundefinedas valid input
- 
Add R.props
- 
Add R.zipWith
- 
Add R.splitAt
- 
Add R.splitWhen
- 
Close Issue #547 - restore readonlydeclaration in Rambda Typescript definitions.
- 
R.append/R.prependnow work only with arrays just like Ramda. Previous behaviour was for them to work with both arrays and strings.
- 
Sync R.plucktypings with@types/ramdaas there was a tiny difference.
6.1.0
- 
Add R.mapIndexed
- 
Add R.filterIndexed
- 
Add R.forEachIndexed
- 
Fix R.andwrong definition, because the function doesn't convert the result to boolean. This introduce another difference with@types/ramda.
- 
Add R.once
- 
Add R.or
6.0.0
- 
Breaking change - R.map/R.filter/R.reject/R.forEach/R.partitiondoesn't pass index as second argument to the predicate, when looping over arrays. The old behaviour of map, filter and forEach can be found in Rambdax methods R.mapIndexed, R.filterIndexed and R.forEachIndexed(introduced in version6.1.0).
- 
Breaking change - R.all/R.none/R.any/R.find/R.findLast/R.findIndex/R.findLastIndexdoesn't pass index as second argument to the predicate.
- 
Add R.applyDiffmethod
- 
Change R.assocPathtypings so the user can explicitly sets type of the new object
- 
Typings of R.assocmatch its@types/ramdacounterpart.
- 
Simplify R.forEachtypings
- 
Remove ReadonlyArray<T>pattern from Typescript definitions - not enough value for the noise it adds.
- 
Fix typing of R.rejectas it wrongly declares that with object, it pass property to predicate.
5.1.0
- 
Add R.takeUntilmethod
- 
Fix wrong R.takeWhile
5.0.0
- 
Deprecate R.changemethod - it does too much; partially replaced withR.updateObject.
- 
Deprecate R.compactmethod - vague use case;R.filterdoes the same job.
- 
R.producealways returns a promise
- 
Add R.updateObjectmethod
- 
Add R.takeWhilemethod
- 
Add R.viewOrmethod
- 
Add R.pipeAsyncmethod
- 
Add R.removeIndexmethod
- 
Add R.excludesmethod
- 
R.includesthrows on wrong input, i.e.R.includes(1, null)
- 
Close Issue #524 - R.assocPathwrong logic when number is used in array path input.
- 
R.mapToObjectAsyncsupports currying
- 
R.mapAsyncLimitsupports currying
- 
Fix R.mapAsyncto pass property to iterator, when input is an object.
- 
Fix currying for several async methods - R.tapAsync,R.produce,R.filterAsync*(extend typings)
4.2.0
- 
Add R.movemethod
- 
Add R.unionmethod
- 
Add R.lensSatisfiesmethod
- 
Add R.mapKeysmethod
- 
Add R.sortByPathmethod
- 
Add R.sortByPropsmethod
- 
Close Issue #519 - ts-toolbeltneeds other type of export with--isolatedModulesflag
4.1.0
- 
R.templateis renamed toR.interpolate
- 
R.equalsnow supports negative zero just likeRamda.equals
- 
Add R.replaceAllmethod
- 
Add R.lensEqmethod
4.0.1
Forgot to export R.of because of wrong marker in files/index.d.ts
4.0.0
Deprecate the following methods:
- R.promiseAllObject- because- R.produceserves the same purpose
- R.composed- because- R.pipedmakes more sense, when we want to pass the input at the start of the function
- R.defaultToStrict- confusing logic
- R.findInObject- overestimated importance
- R.headObject- overestimated importance
- R.includesType- overestimated importance
- R.inject- confusing logic
- R.isAttach- confusing logic
- R.mergeRight- overestimated importance
- R.opposite- overestimated importance
- R.otherwise- overestimated importance
- R.pushUniq- overestimated importance
- R.resolve- overestimated importance
- R.s- overestimated importance
- R.toggle- overestimated importance
- R.uuid- not suitable
- R.whenAsync- overestimated importance
Move the following methods to Rambda and change their logic to match Ramda implementation:
- R.hasPath
- R.unless
- R.pathEq
- R.tryCatch
- R.where
- R.whereEq
Also these changes:
- 
R.flatMap- renamed toR.chainand moved toRambda
- 
R.ifElseAsync- accept any number of arguments for the returned function
- 
R.produce,R.filterAsync,R.debounce,R.throttle- fix typings
- 
R.mapAsyncLimit- drop support for curring and therefore for usage withR.composeAsync
- 
Improve R.okthrowed error message
- 
R.okreturnsundefinedinstead oftruewhen validation passes.
- 
R.mergeDeepis renamed toR.mergeDeepLeft
- 
Add R.pipeAsync
- 
Take R.partialCurryfromRambdaas it is deprecated there
3.7.0
Sync with Rambda
Add R.lens
Add R.lensIndex
Add R.lensPath
Add R.lensProp
Add R.over
Add R.set
Add R.view
Add R.paths
Add R.xor
Add R.cond
3.6.0
- 
Add R.mapAsyncLimit
- 
Add R.toggle, match Ramda upcoming method specification
- 
Add R.isValidAsync
- 
Extend R.templatewithout introducing breaking change
3.5.0 Sync with Rambda - add methods descriptions to Typescript definitions
3.4.0 Sync with Rambda and close Issue #42
3.3.0 Fix R.sortObject typing
3.3.0 Add R.filterAsync and R.sortObject methods
3.2.0 R.uuid accept second argument in order to return string only uuid
3.1.0 Dynamic set of exports lead to adding previously ommited Rambda exports such as R.identical
3.0.3 Sync with Rambda - new functionality of R.isEmpty
3.0.2 Add typings for R.mapToObject
3.0.1 Fix typings
3.0.0 Breaking change as Rambda also has breaking changes
Read more about it in Rambda changelog
Also with this versions, typings tests are provided and several definitions are changed.
- 
R.anyTrue, R.anyFalse, R.allTrue, R.allFalse use internal isTruthyandisFalsymethods. Empty array and object with zero length are considered falsy.
- 
Deprecate R.contains
- 
Deprecate R.defaultToWhen
- 
Moved R.runTeststohelpersrepo
2.17.0 Change in R.runTests logic. It will be removed from Rambdax to helpers repo.
2.16.0 Restore R.runTests but without documentation
- export getEvaluations,getPositiveEvaluation,getNegativeEvaluationin the context ofR.runTests
2.15.0 Several changes
- 
Typescript definitions have been updated and typings tests are introduced 
- 
R.mapAsyncandR.mapFastAsyncpass index as second argument
2.14.1 Restore R.contains
2.14.0 Several changes:
- 
R.injectaccept before flag as fourth argument
- 
Remove R.includesAny
- 
Improve typing of R.partition
- 
R.nextIndexandR.prevIndexwork also with number as second argument
2.13.1 Deprecate R.log and R.runTests
2.12.3 Add 'dist' directory to files
2.12.2 Add R.mapToObject typings
2.12.0 Sync with Rambda
2.11.1 Fix R.waitFor
2.11.0 Add R.toDecimal
2.10.2 Fix issue 32
2.10.0 deprecate R._
2.9.1 R.fromPairs/toPairs typing
2.9.0 npm doesn't update version on their site
2.8.2 R.map typing
2.8.0 Sync with Rambda | no need for create types script
2.7.0 Add R.prevIndex
2.6.2 Sync with Rambda
2.6.0 R.log depends on RAMBDAX_LOG
2.5.0 Rambda's partial
2.4.0 Add R.uuid
2.3.0 R._ parse to constant case
This introduce breaking change for ie11 as noted in issue 31 which is fixed with
2.10.0which deprecates this method
2.2.1 Add R.log, R.logInit and R.logHolder
2.1.0 Add R._
2.0.0 Add R.toggle
1.9.0 Add R.pushUniq
1.8.2 No need for sourcemaps
1.8.1 Fix building with regeneratorRuntime
1.8.0 Upgrade to new major Rollup release
- 
Restore R.headObject
- 
Add R.hasPathmethod
1.7.2 R.memoize contains dev console.logs
1.7.1 Forgot to build types
1.7.0 Rename R.then to R.resolve because of Ramda issue with R.then(they rename it to R.andThen)
- Add R.isFalsy,R.nextIndexandR.mergeDeep
1.6.3 Forgot to export R.unless(credit to @mobily for the PR)
1.6.0 Restore R.compact method
1.5.6 R.maybe accepts also anonymous functions as second and third argument
1.5.5 Add R.maybe method
- Fix errors caugth by DeepScanservice
- Fix Typescript definitions for R.thenandR.otherwise
- R.changeincrease nesting level to 4
1.4.1 R.isValid didn't work with Number prototype
1.4.0 Add multiple methods
- 
Add R.defaultToStrict
- 
Add R.defaultToWhen
- 
Add R.whereEq
- 
Add R.partition
- 
Add R.negateis renamed toR.opposite
- 
Add R.then
- 
Add R.otherwise
- 
R.isValidaccepts prototypes as rules, i.e.schema = {a: String}
- 
The prevoious point leads to the same change applied to the methods depending on R.isValid, i.e.R.ok,R.passandR.isAttach1.3.0 Add R.unless
- 
R.whenaccepts both function and value forwhenTrueargument. The same is valid forR.unless
- 
export R.negatewhich is the same asR.complement1.2.0 Export srcfolder1.1.0 Restore promiseAllObjectandflatMap1.0.1 Fix typings 1.0.0 Deprecate the following methods: 
- 
compact 
- 
evolve 
- 
flatMap 
- 
greater 
- 
intersection 
- 
less 
- 
omitBy 
- 
pickBy 
- 
promiseAllObject 
- 
promiseAllSecure 
- 
rangeBy 
Also pass deprecation of
addIndexfrom[email protected]
0.24.0 add R.pipedAsync, replace R.multiline with R.glue, remove R.validate
0.23.0 Add R.count
0.22.0 Add R.includesAny
0.21.0 Add R.includesType
0.20.1 R.pass and R.ok work with single schema.
0.20.0 Add R.pathEq
0.19.0 Add R.wait, expose already complete R.waitFor
0.18.0 AddR.anyType and R.allType
0.17.0 Rename R.is to R.pass and restore R.is original functionality.
0.16.0 getter, setter, reset methods
0.15.3 No more prepublish script
0.15.2 curry in remove
Last version with
libfolder exposed

❯ Additional info
Most influential contributors
- 
@farwayer - improving performance in R.find, R.filter; give the idea how to make benchmarks more reliable; 
- 
@thejohnfreeman - add R.assoc, R.chain; 
- 
@helmuthdu - add R.clone; help improve code style; 
- 
@jpgorman - add R.zip, R.reject, R.without, R.addIndex; 
- 
@ku8ar - add R.slice, R.propOr, R.identical, R.propIs and several math related methods; introduce the idea to display missing Ramda methods; 
- 
@romgrk - add R.groupBy, R.indexBy, R.findLast, R.findLastIndex; 
- 
@squidfunk - add R.assocPath, R.symmetricDifference, R.difference, R.intersperse; 
- 
@synthet1c - add all lenses methods; add R.applySpec, R.converge; 
- 
@vlad-zhukov - help with configuring Rollup, Babel; change export file to use ES module exports; 
Rambda references
Links to Rambda
- 
[https://mailchi.mp/webtoolsweekly/web-tools-280](Web Tools Weekly) 
- 
https://github.com/stoeffel/awesome-fp-js 
- 
https://github.com/docsifyjs/awesome-docsify 
Deprecated from
Used bysection
- SAP's Cloud SDK - This repo doesn't uses Rambdasince October/2020 commit that removes Rambda
Releases
Rambda's releases before 6.4.0 were used mostly for testing purposes.

My other libraries
| Niketa themeCollection of 9 light VSCode themes | Niketa dark themeCollection of 9 dark VSCode themes | String-fnString utility library | Useful Javascript librariesLarge collection of JavaScript,Typescript and Angular related repos links | Run-fnCLI commands for lint JS/TS files, commit git changes and upgrade of dependencies |