So steuern Sie den Typ von Elementen in einem indexierten TypeScript-Objekt

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum dieses Thema Stack Overflow zum Explodieren bringt?

\n\n

Wenn Sie jemals in TypeScript programmiert und versucht haben, ein Objekt zu erstellen, bei dem alle Werte vom gleichen Typ sein sollen, sind Sie sicherlich auf dieses Problem gestoßen. Die Frage "Enforcing the type of the indexed members of a Typescript object" hat auf Stack Overflow tausende Aufrufe erhalten – nicht ohne Grund, denn es ist ein klassischer Stolperstein für Entwickler, die von JavaScript wechseln.

\n\n

Stellen Sie sich vor: Sie haben ein Cache-Wörterbuch, eine Konfiguration mit dynamischen Schlüsseln oder einfach eine Map mit Zahlen. Sie möchten, dass TypeScript überwacht, dass jeder Wert im Objekt ein String, eine Zahl oder ein komplexer Typ ist. Aber der Compiler lässt Fehler trotzdem durch. Kommt Ihnen das bekannt vor?

\n\n

In diesem Artikel werden wir alle grundlegenden Ansätze zur Lösung dieses Problems durchgehen: von einfachen Index Signatures bis zu fortgeschrittenen Mapped Types. Sie erfahren, wann Sie welche Methode verwenden und welche Fallstricke auf Sie warten.

\n\n

Problem: Objekt mit dynamischen Schlüsseln

\n\n

Angenommen, wir schreiben ein Benutzerverwaltungssystem. Wir haben ein Objekt, bei dem die Schlüssel die Benutzer-IDs und die Werte die Namen der Benutzer sind:

\n\n
interface UserCache {\n  [userId: string]: string;\n}\n\nconst cache: UserCache = {\n  'user_1': 'Alice',\n  'user_2': 'Bob',\n  // 'user_3': 123; // Fehler! Muss ein String sein\n};\n\ncache['user_4'] = 'Charlie'; // OK\ncache['user_5'] = 42; // Fehler! Type 'number' ist nicht zuweisbar zu 'string'\n
\n\n

Es scheint zu funktionieren. Aber es gibt einen Haken: Die Index Signature erlaubt beliebige String-Schlüssel. Was aber, wenn wir die Menge der zulässigen Schlüssel einschränken möchten?

\n\n

Ansatz 1: Index Signature – der Klassiker

\n\n

Index Signature ist der einfachste Weg, den Typ für alle Werte eines Objekts festzulegen. Die Syntax:

\n\n
interface StringMap {\n  [key: string]: string;\n}\n\nconst map: StringMap = {\n  hello: 'world',\n  foo: 'bar',\n};\n
\n\n

Vorteile:

\n
    \n
  • Einfachheit und Lesbarkeit
  • \n
  • Funktioniert mit beliebig vielen Schlüsseln
  • \n
\n\n

Nachteile:

\n
    \n
  • Schlüsselmenge kann nicht eingeschränkt werden
  • \n
  • Alle Werte müssen vom gleichen Typ sein (oder ein Union-Typ)
  • \n
  • Funktioniert nicht mit undefined-Werten (Vorsicht ist geboten)
  • \n
\n\n

Ein häufiger Anfängerfehler: Der Versuch, einem solchen Objekt eine Methode hinzuzufügen:

\n\n
interface BadMap {\n  [key: string]: string;\n  length: number; // Fehler! 'number' ist nicht zuweisbar zu 'string'\n}\n
\n\n

Das funktioniert nicht, weil length den allgemeinen Typ verletzt. Wenn Sie Typen mischen müssen, verwenden Sie Union-Typen oder Mapped Types.

\n\n

Ansatz 2: Record – eingebauter Helfer

\n\n

TypeScript bietet den eingebauten Typ Record<K, V>, der dasselbe tut, aber mit einer prägnanteren Syntax:

\n\n
type StringRecord = Record<string, string>;\n\nconst config: StringRecord = {\n  apiUrl: 'https://api.example.com',\n  timeout: '5000', // OK, String\n  // port: 8080, // Fehler!\n};\n\n// Schlüssel können eingeschränkt werden:\ntype AllowedKeys = 'name' | 'email' | 'phone';\ntype UserRecord = Record<AllowedKeys, string>;\n\nconst user: UserRecord = {\n  name: 'Alice',\n  email: 'alice@example.com',\n  phone: '+1234567890',\n  // age: '30', // Fehler! 'age' ist nicht in AllowedKeys enthalten\n};\n
\n\n

Wann verwenden:

\n
    \n
  • Wenn Sie schnell ein typisiertes Wörterbuch erstellen möchten
  • \n
  • Wenn die Schlüssel eine bestimmte Menge von Werten sind (Union-Typ)
  • \n
  • Für Konfigurationen mit bekannten Feldern
  • \n
\n\n

Nachteil: Record erlaubt es nicht, unterschiedliche Typen für verschiedene Schlüssel festzulegen. Dafür gibt es Mapped Types.

\n\n

Ansatz 3: Map – Alternative aus ES6

\n\n

Wenn Sie die Map aus JavaScript verwenden, typisiert TypeScript sie hervorragend

Blogs

Buchempfehlungen