Installation
npx fragmen add object/deep-equalSource Code
/**
* Performs deep equality comparison between two values
* @param a First value
* @param b Second value
* @returns True if deeply equal, false otherwise
* @example
* deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } })
* // true
*
* deepEqual([1, 2, 3], [1, 2, 3])
* // true
*
* deepEqual({ a: 1 }, { a: 2 })
* // false
*
* deepEqual(null, null)
* // true
*
* deepEqual(undefined, null)
* // false
*/
export function deepEqual(a: unknown, b: unknown): boolean {
// Same reference or both primitive and equal
if (a === b) {
return true;
}
// Handle null explicitly (typeof null === 'object')
if (a === null || b === null) {
return false;
}
if (a === undefined || b === undefined) {
return false;
}
// Different types
if (typeof a !== typeof b) {
return false;
}
// Handle primitives
if (typeof a !== 'object' || typeof b !== 'object') {
return false;
}
// Handle dates
if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime();
}
// Handle arrays
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (!deepEqual(a[i], b[i])) {
return false;
}
}
return true;
}
// One is array, other is not
if (Array.isArray(a) !== Array.isArray(b)) {
return false;
}
// Handle objects
const keysA = Object.keys(a as Record<string, unknown>);
const keysB = Object.keys(b as Record<string, unknown>);
if (keysA.length !== keysB.length) {
return false;
}
for (const key of keysA) {
if (!keysB.includes(key)) {
return false;
}
if (
!deepEqual(
(a as Record<string, unknown>)[key],
(b as Record<string, unknown>)[key]
)
) {
return false;
}
}
return true;
}
Examples
deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } })
// true
deepEqual([1, 2, 3], [1, 2, 3])
// true
deepEqual({ a: 1 }, { a: 2 })
// false
deepEqual(null, null)
// true
deepEqual(undefined, null)
// falseRelated Utilities
clone
objectCreates a deep copy of an object. Recursively clones all properties of an object, including nested objects and arrays. Handles circular references by maintaining a reference map. Primitive values, functions, and built-in objects like Date and RegExp are handled appropriately.
has-path
objectChecks if a nested property path exists in an object. Safely traverses nested object properties using a dot-notation path string or an array of keys. Returns true if the path exists (even if the final value is undefined), false if any part of the path is missing.
merge
objectChecks if a value is a non-array, non-null object.
omit
objectCreates a new object by omitting specified keys from the source object. Returns a new object that contains all properties from the source object except for the specified keys. This is the opposite of the pick utility. The operation is shallow - nested objects are not deeply omitted.
pick
objectCreates a new object composed of the picked object properties. Extracts only the specified keys from the source object, creating a new object with just those properties. Non-existent keys are silently ignored.
Quick Actions
Parameters
aanyFirst value
banySecond value
Returns
unknownTrue if deeply equal, false otherwise