EnglishGitHub
teilweisepackages/better-map/src

Better Map

@ralphschuler/better-map

Aktualisiert, filtert und vereinigt Map-Einträge mit explizitem Verhalten für fehlende Werte.

Mapcollectionsmerge

01 · Problem

Wofür braucht man das?

Beim Arbeiten mit Maps wiederholen sich Muster wie get-transform-set, selektives Kopieren und Konfliktauflösung beim Zusammenführen.

02 · Denkmodell

Das mentale Modell

Map bleibt die Datenstruktur; Helfer sollten lediglich atomare Collection-Operationen ausdrücken und klar sagen, ob sie die Instanz mutieren oder eine neue erzeugen.

Im Repository

Aktualisiert, filtert und vereinigt Map-Einträge mit explizitem Verhalten für fehlende Werte. Werte behalten ihre Referenzidentität; Callbacks sind synchron und können werfen.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Mit has zwischen fehlendem Schlüssel und vorhandenem undefined unterscheiden.
  2. Vorhandenen Wert aktualisieren oder einen expliziten Initialwert erzeugen.
  3. Das Ergebnis genau einmal per set speichern.
  4. Bei Merge-Konflikten eine dokumentierte Resolver-Funktion anwenden.

04 · Bauteile

Die entscheidenden Verträge

updateTransformiert vorhandene Werte oder initialisiert fehlende Einträge.
filter / mergeFiltert in eine neue Map oder vereinigt mutierend.

05 · Selbst bauen

Selbst implementieren

Der wichtigste Entwurfspunkt ist nicht die Vererbung, sondern eine eindeutige Abwesenheits- und Mutationssemantik.

  1. Prüfe Existenz immer mit has statt über den gelesenen Wert.
  2. Trenne create und update, damit undefined nicht als versteckter Initialwert dient.
  3. Lass mutierende Methoden this zurückgeben oder benenne immutable Varianten ausdrücklich.
Konzeptskizze · kann ausgelassene Helfer verwenden
class UpdatingMap<K, V> extends Map<K, V> {
  update(key: K, change: (value: V) => V, create: () => V): this {
    const next = this.has(key) ? change(this.get(key) as V) : create();
    this.set(key, next);
    return this;
  }

  select(predicate: (value: V, key: K) => boolean) {
    const result = new UpdatingMap<K, V>();
    for (const [key, value] of this) {
      if (predicate(value, key)) result.set(key, value);
    }
    return result;
  }
}

06 · Verifizieren

Was solltest du testen?

  • Fehlender Schlüssel, vorhandenes undefined und vorhandenes null bleiben unterscheidbar.
  • Filter verändert die Quelle nicht und erhält Schlüssel-Wert-Paare.
  • Merge-Resolver wird ausschließlich bei echten Konflikten aufgerufen.

Selbst ausprobieren

Formuliere die erste Prüfaussage als fehlschlagenden Test, implementiere die kleinste Korrektur und ergänze einen Grenzfall.

Fehlender Schlüssel, vorhandenes undefined und vorhandenes null bleiben unterscheidbar.

Ansatz vergleichen

Dein Test sollte beim gezielten Verletzen der Invariante fehlschlagen und nach der Korrektur wieder bestehen. Halte den Aufbau deterministisch und prüfe ein beobachtbares Ergebnis.

07 · Grenzen

Kompromisse und Stolperfallen

  • Unterklassen nativer Collections können bei Serialisierung und Cross-Realm-Nutzung überraschen.
  • Mutierende und immutable Operationen in derselben API brauchen besonders klare Namen.
Wichtig

Werte behalten ihre Referenzidentität; Callbacks sind synchron und können werfen.

08 · Weiterdenken

Quellcode und verwandte Ideen

yarn tsx packages/better-map/examples/basic.ts