JavaScript Deep Utility Functions
js-utils-deep is a lightweight JavaScript utility package providing a focused set of functions for deep, recursive manipulation of objects. It includes `recursiveOmit`, which removes null, empty string, and undefined values from all nested levels of an object; `deepExtend`, designed for deeply merging properties from a source object into a target object; and `diffObject`, which identifies key-value differences between two objects, including nested structures. Currently at version 1.1.4, the library appears to be in a maintenance phase, offering stable and tested functionalities without frequent updates. Its primary differentiator is its straightforward API for common deep object tasks, providing essential recursive utilities without the added complexity of larger, more generalized utility libraries.
Common errors
-
RangeError: Maximum call stack size exceeded
cause An object with circular references was passed to a recursive function like `recursiveOmit` or `deepExtend`.fixInspect the object structure for circular references. Refactor your object to avoid them, or preprocess the object to break cycles (e.g., by setting circular references to `null`) before passing it to `js-utils-deep` functions. -
TypeError: Cannot convert undefined or null to object
cause Attempting to call a deep utility function (e.g., `deepExtend`, `recursiveOmit`) with `null` or `undefined` as a primary object argument.fixEnsure all arguments passed to `js-utils-deep` functions, especially the target or source objects, are valid JavaScript objects (non-null, non-undefined). -
TypeError: Cannot set properties of undefined (setting 'propertyName')
cause This error can occur within `deepExtend` if a nested property path in the source object points to an `undefined` or `null` path in the target object where it's attempting to create a new object or set a value.fixEnsure that intermediate objects exist in the target where `deepExtend` is expected to merge. For example, if `source.a.b` exists, but `target.a` is `undefined`, `deepExtend` might fail. Pre-initialize empty objects for paths if necessary, or ensure your target object's structure is compatible with the source.
Warnings
- gotcha Both `deepExtend` and `recursiveOmit` functions mutate their first argument (the target object) in place. If you need to preserve the original object, ensure you pass a deep clone of it as the first argument.
- gotcha Functions that perform deep object traversal, such as `recursiveOmit`, `deepExtend`, and `diffObject`, may encounter infinite loops and throw a 'Maximum call stack size exceeded' error if presented with objects containing circular references.
- gotcha The `recursiveOmit` function treats empty strings `''` as values to be omitted, similar to `null` and `undefined`. Be aware of this behavior if empty strings have semantic meaning in your data and should be preserved.
Install
-
npm install js-utils-deep -
yarn add js-utils-deep -
pnpm add js-utils-deep
Imports
- recursiveOmit
const { recursiveOmit } = require('js-utils-deep');import { recursiveOmit } from 'js-utils-deep'; - deepExtend
import * as deepUtils from 'js-utils-deep'; deepUtils.deepExtend(...);
import { deepExtend } from 'js-utils-deep'; - All functions (CommonJS)
const deepExtend = require('js-utils-deep/deepExtend');const { recursiveOmit, deepExtend, diffObject } = require('js-utils-deep');
Quickstart
import { recursiveOmit, deepExtend, diffObject } from 'js-utils-deep';
// Example for recursiveOmit: Removes null, '', undefined from deeply nested objects
let objToOmit = {
x: {
y: {
z: ''
},
a: {
b: null,
c: undefined
},
d: null
},
e: 0,
f: 'hello',
g: []
};
console.log('Original object for omit:', JSON.stringify(objToOmit));
const omitted = recursiveOmit(objToOmit); // Mutates objToOmit
console.log('Object after recursiveOmit:', JSON.stringify(omitted));
// Expected: {"e":0,"f":"hello","g":[]}
// Example for deepExtend: Deeply merges source into target object
let targetObj = {
x: {
y: { z: '' },
a: { b: null, c: undefined }
},
existing: 'value'
};
let sourceObj = {
x: {
y: { z: 'new_z' },
a: { b: 'new_b', c: 'new_c' },
d: 'new_d'
},
newProp: 'added'
};
console.log('Target object before extend:', JSON.stringify(targetObj));
deepExtend(targetObj, sourceObj); // Mutates targetObj
console.log('Target object after deepExtend:', JSON.stringify(targetObj));
// Expected: {"x":{"y":{"z":"new_z"},"a":{"b":"new_b","c":"new_c"},"d":"new_d"},"existing":"value","newProp":"added"}
// Example for diffObject: Compares two objects and returns differing key-value pairs
let obj1 = {
id: 1,
name: 'Alpha',
details: { version: '1.0', status: 'active' }
};
let obj2 = {
id: 1,
name: 'Beta',
details: { version: '1.1', owner: 'Org' },
tags: ['new']
};
console.log('Object 1 for diff:', JSON.stringify(obj1));
console.log('Object 2 for diff:', JSON.stringify(obj2));
const differences = diffObject(obj1, obj2);
console.log('Differences between objects:', JSON.stringify(differences));
// Expected: {"name":"Beta","details":{"version":"1.1","status":"active","owner":"Org"},"tags":["new"]}