or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-fast-equals

A blazing fast equality comparison library for JavaScript and TypeScript

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/fast-equals@4.0.x

To install, run

npx @tessl/cli install tessl/npm-fast-equals@4.0.0

index.mddocs/

Fast Equals

Fast Equals is a blazing fast equality comparison library for JavaScript and TypeScript that provides both deep and shallow equality comparisons. It handles complex data types including NaN, Date objects, RegExp objects, Map/Set collections, Promise objects, and React elements with specialized high-performance algorithms and optional circular reference support.

Package Information

  • Package Name: fast-equals
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install fast-equals

Core Imports

import { deepEqual, shallowEqual, circularDeepEqual, circularShallowEqual, sameValueZeroEqual, createCustomEqual, createCustomCircularEqual } from "fast-equals";

For CommonJS:

const { deepEqual, shallowEqual, circularDeepEqual, circularShallowEqual, sameValueZeroEqual, createCustomEqual, createCustomCircularEqual } = require("fast-equals");

Basic Usage

import { deepEqual, shallowEqual } from "fast-equals";

// Deep equality comparison
const objA = { foo: { bar: "baz" } };
const objB = { foo: { bar: "baz" } };

console.log(objA === objB); // false
console.log(deepEqual(objA, objB)); // true

// Shallow equality comparison
const nestedObject = { bar: "baz" };
const shallowA = { foo: nestedObject };
const shallowB = { foo: nestedObject };
const shallowC = { foo: { bar: "baz" } };

console.log(shallowEqual(shallowA, shallowB)); // true (same reference)
console.log(shallowEqual(shallowA, shallowC)); // false (different references)

Architecture

Fast Equals is built around several key components:

  • Core Comparators: Optimized functions for deep and shallow equality with different performance characteristics
  • Circular Support: Specialized variants that handle circular references using WeakMap-based caching
  • Type-Specific Handlers: Dedicated comparison logic for different data types (arrays, objects, dates, maps, sets, regexps)
  • Custom Comparator Factory: Extensible system for creating custom equality comparators with user-defined behavior
  • SameValueZero Compliance: Handles NaN equality and other edge cases according to ECMAScript specifications

Capabilities

Deep Equality Comparison

Performs comprehensive deep equality comparison on objects with full type support and optimized performance.

/**
 * Whether the items passed are deeply-equal in value.
 * @param a - First value to compare
 * @param b - Second value to compare
 * @returns Boolean indicating deep equality
 */
function deepEqual<A, B>(a: A, b: B): boolean;

Usage Examples:

import { deepEqual } from "fast-equals";

// Primitive comparison
deepEqual(42, 42); // true
deepEqual("hello", "hello"); // true
deepEqual(NaN, NaN); // true

// Object comparison
deepEqual({ a: 1, b: { c: 3 } }, { a: 1, b: { c: 3 } }); // true
deepEqual([1, [2, 3]], [1, [2, 3]]); // true

// Date comparison
deepEqual(new Date("2023-01-01"), new Date("2023-01-01")); // true

// Map comparison (keys and values are compared deeply)
const map1 = new Map([[{ key: "value" }, "data"]]);
const map2 = new Map([[{ key: "value" }, "data"]]);
deepEqual(map1, map2); // true

// Set comparison
deepEqual(new Set([1, 2, 3]), new Set([3, 2, 1])); // true

Shallow Equality Comparison

Performs shallow equality comparison where nested objects are compared by reference only.

/**
 * Whether the items passed are shallowly-equal in value.
 * @param a - First value to compare
 * @param b - Second value to compare
 * @returns Boolean indicating shallow equality
 */
function shallowEqual<A, B>(a: A, b: B): boolean;

Usage Examples:

import { shallowEqual } from "fast-equals";

const shared = { nested: "value" };
const obj1 = { a: 1, b: shared };
const obj2 = { a: 1, b: shared };
const obj3 = { a: 1, b: { nested: "value" } };

shallowEqual(obj1, obj2); // true (same references)
shallowEqual(obj1, obj3); // false (different references for b)

// Array shallow comparison
shallowEqual([1, 2, shared], [1, 2, shared]); // true
shallowEqual([1, 2, { x: 1 }], [1, 2, { x: 1 }]); // false

Circular Reference Support

Specialized equality comparisons that handle circular references safely using WeakMap-based caching.

/**
 * Whether the items passed are deeply-equal in value, including circular references.
 * @param a - First value to compare
 * @param b - Second value to compare
 * @returns Boolean indicating deep equality with circular support
 */
function circularDeepEqual<A, B>(a: A, b: B): boolean;

/**
 * Whether the items passed are shallowly-equal in value, including circular references.
 * @param a - First value to compare
 * @param b - Second value to compare
 * @returns Boolean indicating shallow equality with circular support
 */
function circularShallowEqual<A, B>(a: A, b: B): boolean;

Usage Examples:

import { circularDeepEqual, circularShallowEqual } from "fast-equals";

// Circular object example
function createCircular(value: string) {
  const obj: any = {
    me: {
      deeply: {
        nested: {
          reference: null, // Will be set to obj
        },
      },
    },
    value,
  };
  obj.me.deeply.nested.reference = obj;
  return obj;
}

const circular1 = createCircular("foo");
const circular2 = createCircular("foo");
const circular3 = createCircular("bar");

circularDeepEqual(circular1, circular2); // true
circularDeepEqual(circular1, circular3); // false

// Circular array example
const array: any[] = ["foo"];
array.push(array);

circularShallowEqual(array, ["foo", array]); // true

SameValueZero Equality

Performs SameValueZero comparison according to ECMAScript specification.

/**
 * Whether the values passed are strictly equal or both NaN.
 * @param a - First value to compare
 * @param b - Second value to compare
 * @returns Boolean indicating SameValueZero equality
 */
function sameValueZeroEqual<A, B>(a: A, b: B): boolean;

Usage Examples:

import { sameValueZeroEqual } from "fast-equals";

sameValueZeroEqual(1, 1); // true
sameValueZeroEqual(NaN, NaN); // true
sameValueZeroEqual(0, -0); // true
sameValueZeroEqual(1, "1"); // false
sameValueZeroEqual({}, {}); // false (different object references)

Custom Comparator Creation

Factory functions for creating custom equality comparators with user-defined behavior for specific use cases.

/**
 * Create a custom equality comparison method.
 * @param getComparatorOptions - Function that receives default options and returns custom overrides
 * @returns Custom equality comparator function
 */
function createCustomEqual<Meta = undefined>(
  getComparatorOptions: GetComparatorOptions<Meta>
): EqualityComparator<Meta>;

/**
 * Create a custom equality comparison method that handles circular references.
 * @param getComparatorOptions - Function that receives default options and returns custom overrides
 * @returns Custom circular equality comparator function
 */
function createCustomCircularEqual<Meta extends BaseCircularMeta = WeakMap<any, any>>(
  getComparatorOptions: GetComparatorOptions<Meta>
): EqualityComparator<Meta>;

Usage Examples:

import { createCustomEqual, createCustomCircularEqual } from "fast-equals";

// Create custom comparator that ignores RegExp flags
const customEqual = createCustomEqual((defaultOptions) => ({
  areRegExpsEqual: (a, b) => a.source === b.source, // Ignore flags
}));

const regex1 = /test/gi;
const regex2 = /test/m;
customEqual(regex1, regex2); // true (same source, flags ignored)

// Create custom circular comparator for legacy environments
const customCircularEqual = createCustomCircularEqual((defaultOptions) => ({
  // Use custom cache implementation instead of WeakMap
  createIsNestedEqual: (comparator) => {
    const cache = new Map(); // Fallback for environments without WeakMap
    return (a, b, indexOrKeyA, indexOrKeyB, parentA, parentB, meta) => {
      // Custom circular detection logic
      return comparator(a, b, meta);
    };
  },
}));

Types

/**
 * Base interface for circular reference metadata
 */
interface BaseCircularMeta extends Pick<WeakMap<any, any>, 'delete' | 'get'> {
  set(key: object, value: any): any;
}

/**
 * Configuration options for comparator creators
 */
interface CreateComparatorCreatorOptions<Meta> {
  areArraysEqual: TypeEqualityComparator<any, Meta>;
  areDatesEqual: TypeEqualityComparator<any, Meta>;
  areMapsEqual: TypeEqualityComparator<any, Meta>;
  areObjectsEqual: TypeEqualityComparator<any, Meta>;
  areRegExpsEqual: TypeEqualityComparator<any, Meta>;
  areSetsEqual: TypeEqualityComparator<any, Meta>;
  createIsNestedEqual: EqualityComparatorCreator<Meta>;
}

/**
 * Function type for getting comparator options
 */
type GetComparatorOptions<Meta> = (
  defaultOptions: CreateComparatorCreatorOptions<Meta>
) => Partial<CreateComparatorCreatorOptions<Meta>>;

/**
 * Internal equality comparator used by the system
 */
type InternalEqualityComparator<Meta> = (
  a: any,
  b: any,
  indexOrKeyA: any,
  indexOrKeyB: any,
  parentA: any,
  parentB: any,
  meta: Meta
) => boolean;

/**
 * Conditional type for equality comparators based on Meta parameter
 */
type EqualityComparator<Meta> = Meta extends undefined
  ? <A, B>(a: A, b: B, meta?: Meta) => boolean
  : <A, B>(a: A, b: B, meta: Meta) => boolean;

/**
 * Creates internal equality comparator from external one
 */
type EqualityComparatorCreator<Meta> = (
  fn: EqualityComparator<Meta>
) => InternalEqualityComparator<Meta>;

/**
 * Simple equality comparator without metadata
 */
type NativeEqualityComparator = <A, B>(a: A, b: B) => boolean;

/**
 * Typed equality comparator for specific types
 */
type TypeEqualityComparator<Type, Meta> = (
  a: Type,
  b: Type,
  isEqual: InternalEqualityComparator<Meta>,
  meta: Meta
) => boolean;