Menu

TypeScript Map: Map<K, V>, get, set, has und Iterieren

Map in TypeScript verwenden: eine typisierte Map<K, V> erzeugen, warum get V | undefined zurückgibt, set, has und delete, Iteration in Einfügereihenfolge, Objekte als Schlüssel, Umwandlung in und aus Objekten und JSON, Map vs Objekt vs Record und array.map() typisieren.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Eine TypeScript-Map ist die eingebaute Map von JavaScript mit typisierten Schlüsseln und Werten: Map<string, number> bildet Strings auf Zahlen ab. Erzeuge eine mit new Map<K, V>() und nutze dann set, get, has und delete. get gibt V | undefined zurück, weil der Schlüssel fehlen kann.

Erst die Typargumente machen eine Map in TypeScript nützlich: Jedes set wird geprüft, und jedes get liefert den Werttyp. Die letzte Zeile ist ein Compilerfehler (TS2345); @ts-expect-error lässt den Block weiterlaufen.

Diese Seite behandelt die Sammlung Map. Wenn du nach array.map() gesucht hast, das steht im letzten Abschnitt.

Eine Map erzeugen

Die Typen kommen aus Typargumenten, aus Anfangseinträgen oder aus einer Annotation. Anfangseinträge sind ein Array von [key, value]-Tupeln oder alles andere, das solche liefert.

Zwei Fallen bei der Inferenz:

  • new Map() ohne Typargumente und ohne Einträge ist Map<any, any>. Nichts, was du hineinlegst oder herausholst, wird geprüft. Schreibe immer new Map<K, V>().
  • Einträge mit unterschiedlichen Werttypen ergeben keine Union. new Map([["a", 1], ["b", "x"]]) ist der Fehler TS2769 (No overload matches this call). Schreibe den Typ aus: new Map<string, number | string>([...]).

get gibt V | undefined zurück

Eine Map kann nicht versprechen, dass ein Schlüssel existiert, daher ist get als V | undefined typisiert. Unter strict musst du dich um das undefined kümmern, bevor du den Wert als V verwendest:

index.ts(4,7): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.

Die Lösungen, von der häufigsten zur seltensten:

TypeScript merkt sich nicht, dass has true zurückgegeben hat, wenn du später get aufrufst. Das Ergebnis von get direkt zu prüfen ist kürzer und sicher. Eine Non-Null-Assertion, stock.get("apples")!, bringt den Fehler zum Schweigen, schützt aber nicht, wenn der Schlüssel fehlt.

Map-Methoden und ihre Typen

MemberTyp auf Map<K, V>Hinweise
new Map<K, V>(entries?)Map<K, V>entries: Iterable von [K, V]
set(key, value)thisFügt hinzu oder ersetzt; verkettbar
get(key)V | undefinedundefined, wenn nicht vorhanden
has(key)boolean
delete(key)booleantrue, wenn etwas entfernt wurde
clear()voidEntfernt alles
sizenumberEine Eigenschaft, keine Methode
keys(), values()Iteratoren von K, VIn ein Array spreaden: [...map.keys()]
entries(), for...ofIterator von [K, V]Einfügereihenfolge
forEach((value, key) => ...)voidAchtung: der Wert kommt zuerst

Über eine Map iterieren

Eine Map wird in Einfügereihenfolge durchlaufen. for...of über die Map liefert [key, value]-Tupel vom Typ [K, V].

Einen vorhandenen Schlüssel neu zu setzen aktualisiert den Wert, behält aber seine ursprüngliche Position in der Reihenfolge.

Objekte als Schlüssel und Zählen

Jeder Wert kann ein Schlüssel sein, auch Objekte und Arrays. Schlüssel werden wie mit === verglichen: Zwei Objekte mit gleichem Inhalt sind verschiedene Schlüssel. Eine Map ist außerdem der übliche Weg, Elemente zu zählen oder zu gruppieren.

Um nach dem Inhalt eines Objekts zu schlüsseln, leite stattdessen einen String oder Zahlenschlüssel ab, etwa user.id oder `${x},${y}`.

Map vs Objekt vs Record

Map<K, V>Objekt / Record<string, V>
Schlüsseltypenbeliebig, verglichen wie mit ===string (Zahlen werden zu Strings), symbol
Typ bei fehlendem Schlüsselget gibt V | undefined zurückobj[key] ist V, außer noUncheckedIndexedAccess ist aktiv
ReihenfolgeEinfügereihenfolgemeist Einfügereihenfolge, aber ganzzahlähnliche Schlüssel kommen zuerst und aufsteigend
Größemap.sizeObject.keys(obj).length
Häufiges Hinzufügen und Löschendafür optimiertnicht dafür optimiert
JSONnicht direkt (JSON.stringify(map) ist "{}")direkt
Literal-Syntax, Destructuringneinja
Versehentlich geerbte Schlüsselkeine"toString" in {} ist true

Faustregel: eine Map für eine Sammlung, deren Schlüssel Daten sind (User-IDs, Wörter, Cache-Einträge) und sich zur Laufzeit ändern; ein Objekttyp oder Record für eine feste Menge bekannter Schlüssel und für alles, was von oder zu JSON geht. Die Seite zum Dictionary vergleicht Index-Signaturen, Record und Map für Lookups mit String-Schlüsseln.

Maps in Objekte und JSON umwandeln

Die Einträge einer Map sind keine Eigenschaften, deshalb sieht JSON.stringify sie nicht. Wandle über Object.fromEntries und Object.entries um:

JSON.parse gibt any zurück, daher legt das as Record<...> fest, was die Daten sein sollen. Es ist keine Prüfung zur Laufzeit; validiere nicht vertrauenswürdiges JSON, bevor du diesem Typ traust.

array.map() typisieren

Viele Suchen nach „typescript map“ meinen die Array-Methode, die jedes Element umwandelt und ein neues Array zurückgibt. Ihr Typ wird aus dem Callback abgeleitet, Annotationen sind also selten nötig:

Den Rückgabetyp des Callbacks zu annotieren ((u): Option => ...) ist der klarste Weg, den Ergebnistyp festzulegen: Eine fehlende oder falsch geschriebene Eigenschaft im zurückgegebenen Objekt ist dann ein Compilerfehler direkt am Callback.

Häufig gestellte Fragen

Wie erzeugt man eine Map in TypeScript?

Übergib dem Konstruktor die Schlüssel und Werttypen: const ages = new Map<string, number>(). Mit Anfangseinträgen werden die Typen abgeleitet: new Map([["ada", 36]]) ist eine Map<string, number>. Ein nacktes new Map() ohne Typen und ohne Einträge ist Map<any, any>, was die Prüfung abschaltet, gib also immer Typen an.

Warum gibt Map.get in TypeScript undefined zurück?

map.get(key) ist als V | undefined typisiert, weil der Schlüssel fehlen könnte. TypeScript verknüpft ein früheres map.has(key) nicht mit einem späteren get, daher musst du selbst nach has undefined behandeln: Speichere das Ergebnis und prüfe es, oder nutze einen Standardwert mit ??.

Was ist der Unterschied zwischen Map und Objekt in TypeScript?

Eine Map akzeptiert Schlüssel jedes Typs (auch Objekte), behält die Einfügereihenfolge, hat eine size und ist für häufiges Hinzufügen und Löschen gebaut. Ein einfaches Objekt oder Record<string, V> hat nur String und Symbol-Schlüssel, lässt sich direkt als JSON serialisieren und unterstützt Literal-Syntax und Destructuring. Nimm eine Map für dynamische Sammlungen mit Schlüsseln, ein Objekt für feste Formen und JSON-Daten.

Wie wandle ich in TypeScript eine Map in ein Objekt oder JSON um?

Object.fromEntries(map) macht aus einer Map<string, V> ein einfaches Objekt, das JSON.stringify dann serialisieren kann. JSON.stringify(map) auf die Map selbst ergibt "{}", weil die Einträge einer Map keine Eigenschaften sind. Der umgekehrte Weg ist new Map(Object.entries(obj)).

Wie typisiere ich den Callback von array.map in TypeScript?

Meist gar nicht: items.map((item) => item.name) leitet item aus dem Array ab und den Ergebnistyp aus dem, was der Callback zurückgibt. Um einen Ergebnistyp zu erzwingen, übergib ihn als Typargument, items.map<string>(...), oder annotiere den Rückgabetyp des Callbacks.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S