Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@astech/deepdiff

saeedhaider29MIT1.0.1TypeScript support: included

A fast, lightweight TypeScript library for comparing deeply nested objects and detecting changes with detailed diff information.

deep, diff, object, json, nested, comparison, cli, typescript, utility, data-diff, js-diff

readme

Deep Object Diff

A fast, lightweight TypeScript library for comparing deeply nested objects and detecting changes with detailed diff information.

Features

  • 🔍 Deep Object Comparison - Compare objects of any depth and complexity
  • 🚀 High Performance - Optimized with circular reference detection
  • 🎯 Detailed Output - Get precise information about what changed, where, and how
  • ⚙️ Configurable - Customize comparison behavior with options
  • 🛠️ Utility Functions - Built-in helpers for filtering and analyzing diffs
  • 📦 Zero Dependencies - Lightweight and tree-shakeable
  • 🎨 TypeScript Support - Full type safety and IntelliSense

Installation

npm install @astech/deepdiff

Basic Usage

import { compare } from "deepdiff";

const objA = {
  user: {
    name: "Alice",
    age: 30,
    hobbies: ["reading", "gaming"],
  },
};

const objB = {
  user: {
    name: "Alice Smith",
    age: 31,
    hobbies: ["reading", "hiking"],
  },
};

const diffs = compare(objA, objB);

console.log(diffs);
// Output:
// [
//   {
//     path: "user.name",
//     type: "changed",
//     before: "Alice",
//     after: "Alice Smith",
//     summary: 'Changed user.name from "Alice" to "Alice Smith"',
//     description: 'Field "user" → "name" changed from "Alice" to "Alice Smith".'
//   },
//   {
//     path: "user.age",
//     type: "changed",
//     before: 30,
//     after: 31,
//     summary: "Changed user.age from 30 to 31",
//     description: 'Field "user" → "age" changed from 30 to 31.'
//   },
//   {
//     path: "user.hobbies.[1]",
//     type: "changed",
//     before: "gaming",
//     after: "hiking",
//     summary: 'Changed user.hobbies.[1] from "gaming" to "hiking"',
//     description: 'Field "user" → "hobbies" → index 1 changed from "gaming" to "hiking".'
//   }
// ]

Advanced Configuration

Compare Options

import { compare, CompareOptions } from "deepdiff";

const options: CompareOptions = {
  // Include null/undefined values in the diff
  includeNulls: true,

  // Custom equality function
  customEqual: (a, b) => Math.abs(a - b) <= 1,

  // Maximum depth to traverse (prevents stack overflow)
  maxDepth: 10,

  // Keys to ignore during comparison
  ignoreKeys: ["timestamp", "id"],

  // Whether to ignore case for string comparisons
  ignoreCase: true,
};

const diffs = compare(objA, objB, options);

Example Use Cases

// Ignore specific fields
const diffs = compare(userA, userB, {
  ignoreKeys: ["lastModified", "version"],
});

// Case-insensitive comparison
const diffs = compare(configA, configB, {
  ignoreCase: true,
});

// Custom tolerance for numbers
const diffs = compare(dataA, dataB, {
  customEqual: (a, b) => {
    if (typeof a === "number" && typeof b === "number") {
      return Math.abs(a - b) < 0.01; // 1% tolerance
    }
    return a === b;
  },
});

Utility Functions

Filtering Diffs

import { compare, filterByType, groupByType } from "deepdiff";

const diffs = compare(objA, objB);

// Filter by change type
const added = filterByType(diffs, "added");
const removed = filterByType(diffs, "removed");
const changed = filterByType(diffs, "changed");

// Group all diffs by type
const groups = groupByType(diffs);
console.log(groups);
// {
//   added: [...],
//   removed: [...],
//   changed: [...]
// }

Summary Statistics

import { compare, getSummary } from "deepdiff";

const diffs = compare(objA, objB);
const summary = getSummary(diffs);

console.log(summary);
// {
//   total: 5,
//   added: 2,
//   removed: 1,
//   changed: 2
// }

Quick Checks

import { compare, isDeepEqual, getChangedPaths } from "deepdiff";

// Check if objects are deeply equal
const areEqual = isDeepEqual(objA, objB);

// Get just the paths that changed
const changedPaths = getChangedPaths(diffs);
// ['user.name', 'user.age', 'user.hobbies.[1]']

Error Handling

The library provides clear error messages for invalid inputs:

// Missing objects
compare(undefined, objB); // Error: "Both objects must be provided for comparison"

// Non-objects
compare("string", objB); // Error: "Both parameters must be objects for comparison"

// Null values
compare(null, objB); // Error: "Both objects must be provided for comparison"

Performance Features

  • Circular Reference Detection: Prevents infinite loops
  • Depth Limiting: Configurable maximum depth to prevent stack overflow
  • Efficient Traversal: Uses generators for memory efficiency
  • Early Termination: Stops comparison when objects are identical

API Reference

compare(a, b, options?)

Main comparison function.

Parameters:

  • a (object): First object to compare
  • b (object): Second object to compare
  • options (CompareOptions, optional): Configuration options

Returns: DiffResult[]

CompareOptions

interface CompareOptions {
  includeNulls?: boolean; // Include null/undefined values
  customEqual?: (a: any, b: any) => boolean; // Custom equality function
  maxDepth?: number; // Maximum traversal depth
  ignoreKeys?: string[]; // Keys to ignore
  ignoreCase?: boolean; // Case-insensitive string comparison
}

DiffResult

interface DiffResult {
  path: string; // Dot-notation path to the change
  type: "added" | "removed" | "changed";
  before?: any; // Previous value
  after?: any; // New value
  summary: string; // Human-readable summary
  description: string; // Detailed description
}

Utility Functions

  • filterByType(diffs, type) - Filter diffs by change type
  • groupByType(diffs) - Group diffs by type
  • getSummary(diffs) - Get summary statistics
  • isDeepEqual(a, b, options?) - Check if objects are equal
  • getChangedPaths(diffs) - Get array of changed paths

CLI Usage

# Compare two JSON files
npx deepdiff file1.json file2.json

# Compare with options
npx deepdiff file1.json file2.json --ignore-keys timestamp,id --max-depth 5

License

MIT