shelving/util/equalmodule

Strict and structural equality predicates used throughout the library. The three tiers — exact, shallow, and deep — map to the same left is T type-guard pattern so they can be used interchangeably anywhere a Match function is expected.

Things to know:

  • isEqual() is a typed wrapper around === — it serves as a type guard, narrowing left to T on true.
  • isShallowEqual() compares one level deep: array items and object props are compared with isEqual (strict ===).
  • isDeepEqual() recurses into nested arrays, objects, and Maps.
  • All structural checks short-circuit on referential equality first (left === right), so passing the same reference always returns true instantly.
  • isObjectEqual() requires the same set of keys — no extra props allowed. Use isObjectMatch() for a subset check.
  • isMapEqual() requires entries in the same insertion order.

Usage

Exact and structural equality

ts
import { isEqual, isShallowEqual, isDeepEqual } from "shelving/util";

isEqual(1, 1);                                     // true
isEqual("a", "b");                                 // false

isShallowEqual({ a: 1 }, { a: 1 });                // true
isShallowEqual({ a: { b: 1 } }, { a: { b: 1 } }); // false (nested object not ===)

isDeepEqual({ a: { b: 1 } }, { a: { b: 1 } });    // true
isDeepEqual([1, [2, 3]], [1, [2, 3]]);             // true

Object and array checks

ts
import { isObjectEqual, isObjectMatch, isArrayEqual, isMapEqual } from "shelving/util";

isObjectEqual({ a: 1, b: 2 }, { a: 1, b: 2 });    // true (exact key match)
isObjectEqual({ a: 1, b: 2 }, { a: 1 });           // false (extra key in left)
isObjectMatch({ a: 1, b: 2 }, { a: 1 });           // true  (subset match)

isArrayEqual([1, 2, 3], [1, 2, 3]);                // true
isArrayEqual([1, 2], [1, 2, 3]);                   // false

// Pass isDeepEqual as recursor for nested structure.
isObjectEqual({ x: [1, 2] }, { x: [1, 2] }, isDeepEqual); // true

Array membership

ts
import { isInArray, isArrayWith } from "shelving/util";

isInArray(["x", "y", "z"], "y");   // true  — is "y" in the array?
isArrayWith(["x", "y"], "x");      // true  — is the left value an array containing "x"?

Comparison predicates

ts
import { isLess, isGreater, isEqualLess, isEqualGreater } from "shelving/util";

isLess(3, 5);         // true
isGreater(5, 3);      // true
isEqualLess(5, 5);    // true

Assertions

ts
import { assertEqual, assertNot } from "shelving/util";

assertEqual(value, expectedValue); // asserts value === expectedValue, narrows type
assertNot(value, null);            // asserts value !== null, narrows type

Functions

Go

assertEqual()function

Assert that two values are exactly (referentially) equal, narrowing left to the type of right.

assertEqual(left: unknown, right: T, caller: AnyCaller = assertEqual): asserts left is T
Go

assertNot()function

Assert that two values are not equal, narrowing left to exclude the type of right.

assertNot(left: T | N, right: N, caller: AnyCaller = assertNot): asserts left is T
Go

isEqual()function

Is unknown value left exactly (referentially) equal to right?

isEqual(left: unknown, right: T): left is T
Go

notEqual()function

Is unknown value left not exactly (referentially) equal to right?

notEqual(left: T | N, right: N): left is T
Go

isLess()function

Is unknown value left less than right (using compareAscending())?

isLess(left: unknown, right: unknown): void
Go

isEqualLess()function

Is unknown value left less than or equal to right (using compareAscending())?

isEqualLess(left: unknown, right: unknown): void
Go

isGreater()function

Is unknown value left greater than right (using compareAscending())?

isGreater(left: unknown, right: unknown): void
Go

isEqualGreater()function

Is unknown value left greater than or equal to right (using compareAscending())?

isEqualGreater(left: unknown, right: unknown): void
Go

isShallowEqual()function

Are two unknown values shallowly equal?

isShallowEqual(left: unknown, right: T): left is T
Go

notShallowEqual()function

Are two unknown values not shallowly equal?

notShallowEqual(left: unknown, right: T): left is T
Go

isDeepEqual()function

Are two unknown values deeply equal?

isDeepEqual(left: unknown, right: T): left is T
Go

notDeepEqual()function

Are two unknown values not deeply equal?

notDeepEqual(left: unknown, right: T): left is T
Go

isMapEqual()function

Are two maps equal based on their items?

isMapEqual(left: ImmutableMap, right: T, recursor: Match = isEqual): left is T
Go

isArrayEqual()function

Are two arrays equal based on their items?

isArrayEqual(left: ImmutableArray, right: T, recursor: Match = isEqual): left is T
Go

isInArray()function

Is unknown value left in array right?

isInArray(left: unknown, right: ImmutableArray<R>): left is R
Go

notInArray()function

Is unknown value left not in array right?

notInArray(left: unknown, right: ImmutableArray): boolean
Go

isArrayWith()function

Is unknown value left an array that includes right?

isArrayWith(left: unknown, right: T): left is ImmutableArray<T>
Go

notArrayWith()function

Is unknown value left not an array, or an array that does not include right?

notArrayWith(left: unknown, right: unknown): boolean
Go

isObjectEqual()function

Are two objects equal based on their own props?

isObjectEqual(left: ImmutableObject, right: T, recursor: Match = isEqual): left is T
Go

isObjectMatch()function

Are two objects partially equal based on their own props?

isObjectMatch(left: L | R, right: R, recursor: Match = isEqual): left is L & R
Go

isObjectWith()function

Is unknown value left an object with every prop from right?

isObjectWith(left: unknown, right: ImmutableObject): boolean
Go

notObjectWith()function

Is unknown value left not an object or missing one or more props from right?

notObjectWith(left: unknown, right: ImmutableObject): boolean