Skip to content

isEqual

Performs deep comparison of two values for equality, supporting objects, arrays, primitive types, etc.

Basic Usage

typescript
import { isEqual } from 'radash'

console.log(isEqual(1, 1))                    // true
console.log(isEqual('hello', 'hello'))        // true
console.log(isEqual([1, 2, 3], [1, 2, 3]))   // true
console.log(isEqual({ a: 1 }, { a: 1 }))     // true
console.log(isEqual(1, '1'))                  // false

Syntax

typescript
function isEqual(a: any, b: any): boolean

Parameters

  • a (any): The first value to compare
  • b (any): The second value to compare

Return Value

Returns a boolean indicating whether the two values are deeply equal.

Examples

Primitive Type Comparison

typescript
import { isEqual } from 'radash'

// Numbers
console.log(isEqual(1, 1))                    // true
console.log(isEqual(1, 2))                    // false
console.log(isEqual(1, '1'))                  // false
console.log(isEqual(0, -0))                   // true
console.log(isEqual(NaN, NaN))                // true

// Strings
console.log(isEqual('hello', 'hello'))        // true
console.log(isEqual('hello', 'world'))        // false
console.log(isEqual('', ''))                  // true

// Booleans
console.log(isEqual(true, true))              // true
console.log(isEqual(false, false))            // true
console.log(isEqual(true, false))             // false

// null and undefined
console.log(isEqual(null, null))              // true
console.log(isEqual(undefined, undefined))    // true
console.log(isEqual(null, undefined))         // false

Array Comparison

typescript
import { isEqual } from 'radash'

// Simple arrays
console.log(isEqual([1, 2, 3], [1, 2, 3]))   // true
console.log(isEqual([1, 2, 3], [1, 2]))      // false
console.log(isEqual([1, 2, 3], [1, 3, 2]))   // false

// Nested arrays
console.log(isEqual([[1, 2], [3, 4]], [[1, 2], [3, 4]])) // true
console.log(isEqual([[1, 2], [3, 4]], [[1, 2], [3, 5]])) // false

// Empty arrays
console.log(isEqual([], []))                  // true
console.log(isEqual([1], []))                 // false

// Mixed type arrays
console.log(isEqual([1, 'hello', true], [1, 'hello', true])) // true
console.log(isEqual([1, 'hello', true], [1, 'hello', false])) // false

Object Comparison

typescript
import { isEqual } from 'radash'

// Simple objects
console.log(isEqual({ a: 1, b: 2 }, { a: 1, b: 2 })) // true
console.log(isEqual({ a: 1, b: 2 }, { b: 2, a: 1 })) // true (property order doesn't matter)
console.log(isEqual({ a: 1, b: 2 }, { a: 1, b: 3 })) // false

// Nested objects
console.log(isEqual(
  { user: { name: 'Alice', age: 25 } },
  { user: { name: 'Alice', age: 25 } }
)) // true

console.log(isEqual(
  { user: { name: 'Alice', age: 25 } },
  { user: { name: 'Bob', age: 25 } }
)) // false

// Empty objects
console.log(isEqual({}, {}))                  // true
console.log(isEqual({ a: 1 }, {}))           // false

Complex Object Comparison

typescript
import { isEqual } from 'radash'

const obj1 = {
  id: 1,
  name: 'Alice',
  profile: {
    email: 'alice@example.com',
    address: {
      city: 'Beijing',
      country: 'China'
    },
    preferences: {
      theme: 'dark',
      notifications: true
    }
  },
  hobbies: ['reading', 'swimming'],
  metadata: {
    createdAt: new Date('2023-01-01'),
    tags: ['user', 'active']
  }
}

const obj2 = {
  id: 1,
  name: 'Alice',
  profile: {
    email: 'alice@example.com',
    address: {
      city: 'Beijing',
      country: 'China'
    },
    preferences: {
      theme: 'dark',
      notifications: true
    }
  },
  hobbies: ['reading', 'swimming'],
  metadata: {
    createdAt: new Date('2023-01-01'),
    tags: ['user', 'active']
  }
}

console.log(isEqual(obj1, obj2)) // true

Function Comparison

typescript
import { isEqual } from 'radash'

const func1 = (x: number) => x * 2
const func2 = (x: number) => x * 2
const func3 = (x: number) => x + 2

console.log(isEqual(func1, func1))            // true (same reference)
console.log(isEqual(func1, func2))            // false (different references)
console.log(isEqual(func1, func3))            // false

Date Comparison

typescript
import { isEqual } from 'radash'

const date1 = new Date('2023-01-01T00:00:00Z')
const date2 = new Date('2023-01-01T00:00:00Z')
const date3 = new Date('2023-01-02T00:00:00Z')

console.log(isEqual(date1, date2))            // true
console.log(isEqual(date1, date3))            // false
console.log(isEqual(date1, '2023-01-01'))    // false

Regular Expression Comparison

typescript
import { isEqual } from 'radash'

const regex1 = /hello/i
const regex2 = /hello/i
const regex3 = /world/i

console.log(isEqual(regex1, regex1))         // true (same reference)
console.log(isEqual(regex1, regex2))         // false (different references)
console.log(isEqual(regex1, regex3))         // false

Special Value Comparison

typescript
import { isEqual } from 'radash'

// NaN comparison
console.log(isEqual(NaN, NaN))                // true
console.log(isEqual(NaN, 0))                  // false

// Infinity comparison
console.log(isEqual(Infinity, Infinity))      // true
console.log(isEqual(-Infinity, -Infinity))    // true
console.log(isEqual(Infinity, -Infinity))     // false

// Zero comparison
console.log(isEqual(0, -0))                   // true
console.log(isEqual(0, 0))                    // true

Circular Reference Handling

typescript
import { isEqual } from 'radash'

const obj1: any = { a: 1 }
obj1.self = obj1

const obj2: any = { a: 1 }
obj2.self = obj2

// Note: Circular references may cause infinite recursion
// Care should be taken in actual usage
console.log(isEqual(obj1, obj2))              // May be true or throw error

Type-Safe Comparison

typescript
import { isEqual } from 'radash'

// Different types of primitive values
console.log(isEqual(1, '1'))                  // false
console.log(isEqual(true, 1))                 // false
console.log(isEqual(null, undefined))         // false
console.log(isEqual([], {}))                  // false

// Same type, different values
console.log(isEqual(1, 2))                    // false
console.log(isEqual('hello', 'world'))        // false
console.log(isEqual(true, false))             // false

Practical Application Scenarios

typescript
import { isEqual } from 'radash'

// Form data comparison
function hasFormChanged(originalData: any, currentData: any) {
  return !isEqual(originalData, currentData)
}

const originalForm = {
  name: 'Alice',
  email: 'alice@example.com',
  preferences: {
    theme: 'dark',
    notifications: true
  }
}

const currentForm = {
  name: 'Alice',
  email: 'alice@example.com',
  preferences: {
    theme: 'light', // Changed
    notifications: true
  }
}

console.log(hasFormChanged(originalForm, currentForm)) // true

Configuration Comparison

typescript
import { isEqual } from 'radash'

function hasConfigChanged(oldConfig: any, newConfig: any) {
  return !isEqual(oldConfig, newConfig)
}

const oldConfig = {
  server: {
    port: 3000,
    host: 'localhost'
  },
  database: {
    url: 'postgresql://localhost:5432/mydb',
    pool: {
      min: 1,
      max: 10
    }
  }
}

const newConfig = {
  server: {
    port: 3000,
    host: 'localhost'
  },
  database: {
    url: 'postgresql://localhost:5432/mydb',
    pool: {
      min: 2, // Changed
      max: 10
    }
  }
}

console.log(hasConfigChanged(oldConfig, newConfig)) // true

State Comparison

typescript
import { isEqual } from 'radash'

function hasStateChanged(oldState: any, newState: any) {
  return !isEqual(oldState, newState)
}

const oldState = {
  user: {
    id: 1,
    name: 'Alice',
    isLoggedIn: true
  },
  settings: {
    theme: 'dark',
    language: 'en'
  }
}

const newState = {
  user: {
    id: 1,
    name: 'Alice',
    isLoggedIn: true
  },
  settings: {
    theme: 'light', // Changed
    language: 'en'
  }
}

console.log(hasStateChanged(oldState, newState)) // true

Cache Key Comparison

typescript
import { isEqual } from 'radash'

class Cache {
  private cache = new Map()

  get(key: any) {
    for (const [cachedKey, value] of this.cache) {
      if (isEqual(cachedKey, key)) {
        return value
      }
    }
    return undefined
  }

  set(key: any, value: any) {
    this.cache.set(key, value)
  }
}

const cache = new Cache()
const params1 = { userId: 1, filter: 'active' }
const params2 = { userId: 1, filter: 'active' }

cache.set(params1, 'cached data')
console.log(cache.get(params2)) // 'cached data' (because isEqual(params1, params2) is true)

Notes

  1. Deep Comparison: Recursively compares all nested properties
  2. Type Strict: Primitive values of different types are not equal
  3. Reference Comparison: Functions and regular expressions are compared by reference
  4. Circular References: May cause infinite recursion
  5. Performance: Comparison may be slow for large objects

Differences from Other Methods

  • ===: Strict equality, does not perform deep comparison
  • ==: Loose equality, performs type conversion
  • isEqual(): Deep comparison method provided by radash

Practical Application Scenarios

  1. State Management: Compare application state changes
  2. Form Validation: Detect form data changes
  3. Cache Management: Compare cache keys
  4. Configuration Management: Detect configuration changes
  5. Testing: Deep comparison of test results

Released under the MIT License.