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.
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?
- Vereinigung aller eigenen Schlüssel beider Objekte bilden.
- Werte mit einer festgelegten Gleichheitsfunktion vergleichen.
- Nur abweichende Paare als before/after erfassen.
- 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.
- Nimm beide Werte explizit als Parameter statt native Prototypen zu patchen.
- Benutze Object.keys und Object.is für ein klares flaches Diff.
- Behandle Deep-Diff, Array-Mengenlogik und Patch-Erzeugung als getrennte Erweiterungen.
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.
Globale Prototype-Erweiterungen sind besonders für Libraries riskant: Ein Import kann fremde Schleifen und andere Polyfills verändern.
08 · Weiterdenken