GitHub
Prototyppackages/complex-compare/src

Complex Compare

@ralphschuler/complex-compare

Berechnet flache Unterschiede zwischen Arrays oder Objektfeldern – idealerweise ohne globale Prototypen zu verändern.

diffobjectspure functions

01 · Problem

Wofür braucht man das?

Konfigurationen und Snapshots müssen häufig zeigen, welche Schlüssel hinzugefügt, entfernt oder verändert wurden.

02 · Denkmodell

Das mentale Modell

Ein Diff ist eine Menge adressierbarer Änderungen mit before und after. Die Vergleichstiefe und Gleichheitssemantik müssen Teil des Vertrags sein.

Im Repository

Das Modul hängt difference enumerable an Array.prototype und Object an, exportiert jedoch nichts. Der Vergleich ist flach und Array-Differenz arbeitet O(n·m).

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Vereinigung aller eigenen Schlüssel beider Objekte bilden.
  2. Werte mit einer festgelegten Gleichheitsfunktion vergleichen.
  3. Nur abweichende Paare als before/after erfassen.
  4. Array-Differenz über ein Set der ausgeschlossenen Werte berechnen.

04 · Bauteile

Die entscheidenden Verträge

Array.prototype.difference (global) Filtert Werte des linken Arrays, die rechts nicht enthalten sind.
Object.difference (global) Erzeugt einen flachen Record aus Tupeln alter und neuer Werte.
DiffResult (intern) Typ für Änderungen, der nicht exportiert wird.

05 · Build it yourself

Selbst implementieren

Pure Funktionen vermeiden Namenskollisionen, enumerable Prototype-Properties und überraschende Seiteneffekte beim Import.

  1. Nimm beide Werte explizit als Parameter statt native Prototypen zu patchen.
  2. Benutze Object.keys und Object.is für ein klares flaches Diff.
  3. Behandle Deep-Diff, Array-Mengenlogik und Patch-Erzeugung als getrennte Erweiterungen.
minimal.ts · unabhängig vom Package
function objectDiff(
  left: Record<string, unknown>,
  right: Record<string, unknown>,
) {
  const keys = new Set([...Object.keys(left), ...Object.keys(right)]);
  const changes = new Map<string, { before: unknown; after: unknown }>();
  for (const key of keys) {
    if (!Object.is(left[key], right[key])) {
      changes.set(key, { before: left[key], after: right[key] });
    }
  }
  return changes;
}

06 · Verifizieren

Was du testen solltest

  • Hinzugefügte, entfernte und auf undefined gesetzte Keys bleiben unterscheidbar.
  • NaN, -0 und Referenzobjekte folgen der dokumentierten Gleichheitssemantik.
  • Der Import verändert weder Array.prototype noch Object und Eingaben bleiben unverändert.

07 · Grenzen

Kompromisse und Stolperfallen

  • Ein flaches Diff ist schnell, erkennt aber Änderungen innerhalb verschachtelter Objekte nicht.
  • Deep-Diffs benötigen Zyklenerkennung und eine definierte Behandlung von Map, Set und Klasseninstanzen.
Wichtig

Globale Prototype-Erweiterungen sind besonders für Libraries riskant: Ein Import kann fremde Schleifen und andere Polyfills verändern.

08 · Weiterdenken

Quellcode und Nachbarn

Originalcode auf GitHub ansehen