CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ramda

A practical functional library for JavaScript programmers.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

object-functions.mddocs/

Object Functions

Ramda provides 57 comprehensive functions for working with objects and their properties. These functions enable immutable object manipulation, property access, and complex object transformations while maintaining functional programming principles.

Property Access

prop

Get a property value from an object.

/**
 * @param {String|Number} key - Property key to access
 * @param {Object} obj - Object to read from
 * @returns {*} Property value or undefined
 */
R.prop(key, obj)

const user = { name: 'John', age: 30, active: true };

R.prop('name', user);        // => 'John'
R.prop('age', user);         // => 30  
R.prop('missing', user);     // => undefined

// Curried usage for data extraction
const getName = R.prop('name');
const users = [{name: 'Alice'}, {name: 'Bob'}];
R.map(getName, users);       // => ['Alice', 'Bob']

props

Get multiple property values as an array.

/**
 * @param {Array} keys - Array of property keys  
 * @param {Object} obj - Object to read from
 * @returns {Array} Array of property values
 */
R.props(keys, obj)

const user = { name: 'John', age: 30, city: 'NYC' };

R.props(['name', 'age'], user);          // => ['John', 30]
R.props(['city', 'name'], user);         // => ['NYC', 'John']  
R.props(['missing', 'name'], user);      // => [undefined, 'John']

// Extract specific fields from objects
const extractInfo = R.props(['id', 'name', 'email']);
const users = [{id: 1, name: 'Alice', email: 'alice@example.com', extra: 'data'}];
R.map(extractInfo, users); // => [[1, 'Alice', 'alice@example.com']]

path

Access nested properties safely.

/**
 * @param {Array} pathArray - Array of keys for nested access
 * @param {Object} obj - Object to traverse
 * @returns {*} Nested property value or undefined
 */
R.path(pathArray, obj)

const user = {
  profile: {
    personal: { name: 'John', age: 30 },
    contact: { email: 'john@example.com' }
  }
};

R.path(['profile', 'personal', 'name'], user);    // => 'John'
R.path(['profile', 'contact', 'email'], user);    // => 'john@example.com'  
R.path(['profile', 'missing', 'field'], user);    // => undefined
R.path(['a', 'b'], { a: { b: 2 } });             // => 2

// Safe access prevents errors
R.path(['deep', 'nested', 'prop'], {});          // => undefined (no error)

pathOr

Access nested properties with default value.

/**
 * @param {*} defaultValue - Value to return if path doesn't exist
 * @param {Array} pathArray - Array of keys for nested access  
 * @param {Object} obj - Object to traverse
 * @returns {*} Nested property value or default
 */
R.pathOr(defaultValue, pathArray, obj)

const config = { api: { timeout: 5000 } };

R.pathOr(3000, ['api', 'timeout'], config);      // => 5000
R.pathOr(3000, ['api', 'retries'], config);      // => 3000 (default)
R.pathOr('Unknown', ['user', 'name'], {});       // => 'Unknown'

Object Copying and Cloning

clone

Create a deep copy of an object or array.

/**
 * @param {*} value - Value to clone (object, array, or primitive)
 * @returns {*} Deep copy of the value
 */
R.clone(value)

const original = {
  name: 'John',
  scores: [85, 90, 78],
  profile: { age: 30, active: true }
};

const copied = R.clone(original);
copied.scores.push(95);              // Original scores unchanged
copied.profile.age = 31;             // Original profile unchanged

// Safe for nested structures
const nestedArray = [[1, 2], [3, 4]];
const clonedArray = R.clone(nestedArray);
clonedArray[0].push(3);              // Original array unchanged

// Handles various data types
R.clone([1, 2, 3]);                  // => [1, 2, 3] (new array)
R.clone({a: 1});                     // => {a: 1} (new object)
R.clone('hello');                    // => 'hello' (primitives return as-is)

Property Modification

assoc

Set a property (immutable).

/**
 * @param {String|Number} key - Property key to set
 * @param {*} value - Value to assign  
 * @param {Object} obj - Object to modify
 * @returns {Object} New object with property set
 */
R.assoc(key, value, obj)

const user = { name: 'John', age: 30 };

R.assoc('age', 31, user);               // => { name: 'John', age: 31 }
R.assoc('city', 'NYC', user);           // => { name: 'John', age: 30, city: 'NYC' }

// Original object unchanged
console.log(user);                      // => { name: 'John', age: 30 }

// Curried usage for object updates
const addTimestamp = R.assoc('timestamp', Date.now());
const withTimestamp = addTimestamp({ data: 'value' });

assocPath

Set nested property (immutable).

/**
 * @param {Array} pathArray - Array of keys for nested access
 * @param {*} value - Value to set at path
 * @param {Object} obj - Object to modify  
 * @returns {Object} New object with nested property set
 */
R.assocPath(pathArray, value, obj)

const user = { profile: { name: 'John', settings: { theme: 'dark' } } };

R.assocPath(['profile', 'name'], 'Jane', user);
// => { profile: { name: 'Jane', settings: { theme: 'dark' } } }

R.assocPath(['profile', 'settings', 'theme'], 'light', user);
// => { profile: { name: 'John', settings: { theme: 'light' } } }

// Create missing intermediate objects
R.assocPath(['new', 'nested', 'prop'], 'value', {});
// => { new: { nested: { prop: 'value' } } }

dissoc

Remove a property (immutable).

/**
 * @param {String} key - Property key to remove
 * @param {Object} obj - Object to modify
 * @returns {Object} New object without the property
 */
R.dissoc(key, obj)

const user = { name: 'John', age: 30, temp: 'remove-me' };

R.dissoc('temp', user);                 // => { name: 'John', age: 30 }
R.dissoc('missing', user);              // => { name: 'John', age: 30, temp: 'remove-me' }

// Remove multiple properties
const removeFields = R.pipe(
  R.dissoc('temp'),
  R.dissoc('internal')
);

dissocPath

Remove nested property (immutable).

/**
 * @param {Array} pathArray - Array of keys for nested access
 * @param {Object} obj - Object to modify
 * @returns {Object} New object without the nested property
 */
R.dissocPath(pathArray, obj)

const user = {
  profile: {
    name: 'John',
    settings: { theme: 'dark', lang: 'en' }
  }
};

R.dissocPath(['profile', 'settings', 'theme'], user);
// => { profile: { name: 'John', settings: { lang: 'en' } } }

Object Transformation

evolve

Transform object properties using functions.

/**
 * @param {Object} transformations - Object mapping keys to transformation functions
 * @param {Object} obj - Object to transform
 * @returns {Object} New object with properties transformed
 */
R.evolve(transformations, obj)

const user = { name: '  john  ', age: '30', active: 'true' };

const transformations = {
  name: R.pipe(R.trim, R.toUpper),
  age: parseInt,
  active: R.equals('true')
};

R.evolve(transformations, user);
// => { name: 'JOHN', age: 30, active: true }

// Nested transformations
const nestedTransform = {
  profile: {
    name: R.toUpper,
    age: R.add(1)
  }
};

R.evolve(nestedTransform, {
  profile: { name: 'john', age: 30 },
  other: 'unchanged'
});
// => { profile: { name: 'JOHN', age: 31 }, other: 'unchanged' }

modify

Transform a specific property.

/**
 * @param {String|Number} key - Property key to modify
 * @param {Function} fn - Transformation function  
 * @param {Object} obj - Object to modify
 * @returns {Object} New object with property transformed
 */
R.modify(key, fn, obj)

const user = { name: 'john', age: 30, scores: [85, 90, 78] };

R.modify('name', R.toUpper, user);              // => { name: 'JOHN', age: 30, scores: [85, 90, 78] }
R.modify('age', R.add(1), user);                // => { name: 'john', age: 31, scores: [85, 90, 78] }
R.modify('scores', R.append(95), user);         // => { name: 'john', age: 30, scores: [85, 90, 78, 95] }

modifyPath

Transform a nested property.

/**
 * @param {Array} pathArray - Array of keys for nested access  
 * @param {Function} fn - Transformation function
 * @param {Object} obj - Object to modify
 * @returns {Object} New object with nested property transformed
 */
R.modifyPath(pathArray, fn, obj)

const state = {
  user: {
    profile: { name: 'john', visits: 5 }
  }
};

R.modifyPath(['user', 'profile', 'name'], R.toUpper, state);
// => { user: { profile: { name: 'JOHN', visits: 5 } } }

R.modifyPath(['user', 'profile', 'visits'], R.inc, state);  
// => { user: { profile: { name: 'john', visits: 6 } } }

Object Merging

merge

Shallow merge two objects.

/**
 * @param {Object} obj1 - First object
 * @param {Object} obj2 - Second object (properties override obj1)
 * @returns {Object} New merged object
 */
R.merge(obj1, obj2)

const defaults = { timeout: 5000, retries: 3 };
const config = { timeout: 8000, debug: true };

R.merge(defaults, config);  
// => { timeout: 8000, retries: 3, debug: true }

// Curried usage for applying defaults
const withDefaults = R.merge({ theme: 'light', lang: 'en' });
withDefaults({ theme: 'dark' }); // => { theme: 'dark', lang: 'en' }

mergeDeepLeft, mergeDeepRight

Deep merge objects with conflict resolution.

const obj1 = {
  a: 1,
  nested: { x: 10, y: 20 }
};

const obj2 = {
  b: 2,  
  nested: { x: 30, z: 40 }
};

// Left object takes precedence
R.mergeDeepLeft(obj1, obj2);
// => { a: 1, b: 2, nested: { x: 10, y: 20, z: 40 } }

// Right object takes precedence  
R.mergeDeepRight(obj1, obj2);
// => { a: 1, b: 2, nested: { x: 30, y: 20, z: 40 } }

mergeWith, mergeDeepWith

Merge objects with custom conflict resolution.

/**
 * @param {Function} conflictFn - Function to resolve conflicts (leftVal, rightVal) -> resolvedVal
 * @param {Object} obj1 - First object
 * @param {Object} obj2 - Second object  
 * @returns {Object} New merged object
 */
R.mergeWith(conflictFn, obj1, obj2)

const obj1 = { a: 1, b: [1, 2], c: 'hello' };
const obj2 = { a: 2, b: [3, 4], d: 'world' };

// Concatenate conflicting arrays, add numbers, take right for others
R.mergeWith(
  (left, right) => {
    if (Array.isArray(left)) return R.concat(left, right);
    if (typeof left === 'number') return left + right;
    return right;
  },
  obj1,
  obj2
);
// => { a: 3, b: [1, 2, 3, 4], c: 'hello', d: 'world' }

Object Introspection

keys, values

Get object keys or values.

const obj = { name: 'John', age: 30, active: true };

R.keys(obj);           // => ['name', 'age', 'active']  
R.values(obj);         // => ['John', 30, true]

// keysIn and valuesIn include inherited properties
function Person(name) { this.name = name; }
Person.prototype.species = 'human';
const john = new Person('John');

R.keys(john);          // => ['name']
R.keysIn(john);        // => ['name', 'species']

toPairs, toPairsIn

Convert object to key-value pairs.

/**
 * @param {Object} obj - Object to convert
 * @returns {Array} Array of [key, value] pairs
 */
R.toPairs(obj)

const obj = { name: 'John', age: 30 };

R.toPairs(obj);        // => [['name', 'John'], ['age', 30]]

// Convert back to object
R.fromPairs([['name', 'John'], ['age', 30]]); // => { name: 'John', age: 30 }

has, hasIn, hasPath

Check property existence.

const obj = { name: 'John', profile: { age: 30 } };

// Own properties only
R.has('name', obj);                    // => true
R.has('toString', obj);                // => false

// Including inherited properties  
R.hasIn('toString', obj);              // => true

// Nested property existence
R.hasPath(['profile', 'age'], obj);    // => true
R.hasPath(['profile', 'email'], obj);  // => false

Object Filtering and Selection

pick, pickAll

Select specific properties.

/**
 * @param {Array} keys - Array of property keys to pick
 * @param {Object} obj - Object to pick from
 * @returns {Object} New object with only selected properties  
 */
R.pick(keys, obj)

const user = { id: 1, name: 'John', email: 'john@example.com', password: 'secret' };

R.pick(['id', 'name'], user);          // => { id: 1, name: 'John' }
R.pick(['name', 'missing'], user);     // => { name: 'John' }

// pickAll includes undefined for missing keys
R.pickAll(['name', 'missing'], user);  // => { name: 'John', missing: undefined }

// Create safe user objects
const safeUser = R.pick(['id', 'name', 'email']);
safeUser(user); // => { id: 1, name: 'John', email: 'john@example.com' }

omit

Exclude specific properties.

/**
 * @param {Array} keys - Array of property keys to omit
 * @param {Object} obj - Object to omit from
 * @returns {Object} New object without specified properties
 */
R.omit(keys, obj)

const user = { id: 1, name: 'John', password: 'secret', temp: 'data' };

R.omit(['password', 'temp'], user);    // => { id: 1, name: 'John' }

// Remove sensitive data
const sanitize = R.omit(['password', 'apiKey', 'secret']);
sanitize(user); // => { id: 1, name: 'John' }

pickBy

Select properties by predicate.

/**
 * @param {Function} predicate - Function to test values (value, key) -> Boolean
 * @param {Object} obj - Object to filter
 * @returns {Object} New object with properties that satisfy predicate
 */
R.pickBy(predicate, obj)

const data = { a: 1, b: 'hello', c: null, d: 42, e: undefined };

R.pickBy(R.is(Number), data);          // => { a: 1, d: 42 }
R.pickBy(R.complement(R.isNil), data); // => { a: 1, b: 'hello', d: 42 }
R.pickBy((val, key) => key.length > 1, { a: 1, bb: 2, ccc: 3 }); // => { bb: 2, ccc: 3 }

Validation and Testing

where, whereEq

Test object properties against specifications.

/**
 * @param {Object} spec - Object mapping keys to predicate functions
 * @param {Object} testObj - Object to test
 * @returns {Boolean} True if all predicates pass
 */
R.where(spec, testObj)

const spec = {
  name: R.is(String),
  age: R.both(R.is(Number), R.gte(R.__, 18)),
  active: R.equals(true)
};

const user1 = { name: 'John', age: 25, active: true };
const user2 = { name: 'Jane', age: 16, active: true };

R.where(spec, user1);                  // => true
R.where(spec, user2);                  // => false (age < 18)

// whereEq tests for exact value equality
const activeUser = R.whereEq({ active: true, status: 'online' });
activeUser({ name: 'John', active: true, status: 'online' }); // => true

eqProps

Compare property values between objects.

/**
 * @param {String} key - Property key to compare
 * @param {Object} obj1 - First object
 * @param {Object} obj2 - Second object  
 * @returns {Boolean} True if property values are equal
 */
R.eqProps(key, obj1, obj2)

const user1 = { name: 'John', age: 30 };
const user2 = { name: 'John', age: 25 };

R.eqProps('name', user1, user2);       // => true
R.eqProps('age', user1, user2);        // => false

Advanced Object Operations

lens, lensProp, lensPath

Create lenses for focused object updates.

// Property lens
const nameLens = R.lensProp('name');
const user = { name: 'john', age: 30 };

R.view(nameLens, user);                // => 'john' (get)
R.set(nameLens, 'Jane', user);         // => { name: 'Jane', age: 30 } (set)
R.over(nameLens, R.toUpper, user);     // => { name: 'JOHN', age: 30 } (transform)

// Path lens for nested access
const profileNameLens = R.lensPath(['profile', 'name']);
const state = { profile: { name: 'john', age: 30 } };

R.over(profileNameLens, R.toUpper, state);
// => { profile: { name: 'JOHN', age: 30 } }

invert, invertObj

Swap keys and values.

const roles = { admin: 'Alice', user: 'Bob', guest: 'Charlie' };

// Simple inversion (last value wins for duplicates)
R.invertObj(roles);        // => { Alice: 'admin', Bob: 'user', Charlie: 'guest' }

// Handle duplicate values with arrays
R.invert({ a: 'x', b: 'y', c: 'x' }); // => { x: ['a', 'c'], y: ['b'] }

These object functions provide a comprehensive toolkit for immutable object manipulation, enabling sophisticated data transformations while maintaining the functional programming paradigm.

Install with Tessl CLI

npx tessl i tessl/npm-ramda

docs

function-functions.md

index.md

list-functions.md

math-logic.md

object-functions.md

string-type.md

tile.json