Einleitung: Die ewige Frage auf Stack Overflow
\n\nHaben Sie sich jemals gefragt, wie erfahrene TypeScript-Entwickler die Namen von enum-Werten erhalten? Wenn Sie auf Stack Overflow waren, haben Sie sicherlich die Frage mit tausenden von Aufrufen gesehen: "How to get names of enum entries?". Es scheint einfach, aber in der Praxis stolpern viele Anfänger (und nicht nur sie) über diese Stelle.
In diesem Artikel geben wir nicht nur eine fertige Antwort. Wir schauen unter die Haube von TypeScript und analysieren, wie enum genau funktioniert, wie der Compiler sie in JavaScript umwandelt und warum einige Ansätze zum Abrufen von Namen zu unerwarteten Fehlern führen können. Bereit? Los geht's!
Was ist ein Enum in TypeScript und wozu braucht man ihre Namen?
\n\nEin Enum (Aufzählung) ist eine praktische Möglichkeit, einen Satz benannter Konstanten zu definieren. In TypeScript gibt es numerische (standardmäßig) und stringbasierte Enums. Aber was tun, wenn Sie den Namen eines bestimmten Werts benötigen? Zum Beispiel erhalten Sie von einer API den Statuscode 403 und möchten dem Benutzer eine verständliche Meldung "Forbidden" anzeigen.
enum HttpStatus {\n OK = 200,\n NotFound = 404,\n Forbidden = 403\n}\n\n// Unsere Aufgabe: Den Namen "Forbidden" zum Wert 403 erhalten\n\n\nEs scheint, dass TypeScript eine eingebaute Methode dafür bereitstellen sollte. Aber nein. Man muss seine eigene Logik schreiben. Und hier wird es interessant.
\n\nDie "einfache" Lösung: Object.keys und Object.values
\n\nDer naheliegendste Weg ist die Verwendung der Methoden Object.keys() oder Object.values(). Viele Anfänger schreiben so etwas:
function getEnumName(enumObj: any, value: number): string | undefined {\n const keys = Object.keys(enumObj);\n return keys.find(key => enumObj[key] === value);\n}\n\nconsole.log(getEnumName(HttpStatus, 403)); // "Forbidden" — funktioniert!\n\n\nSieht logisch aus, oder? Aber wenn Sie diesen Code mit einem numerischen Enum ausprobieren, erwartet Sie eine Überraschung. Schauen wir uns an, wozu unser HttpStatus kompiliert wird.
Unter der Haube: Kompilierung eines numerischen Enums
\n\nWenn TypeScript ein numerisches Enum kompiliert, erstellt es ein Objekt mit Reverse Mapping. So sieht der kompilierte JavaScript-Code aus:
\n\nvar HttpStatus;\n(function (HttpStatus) {\n HttpStatus[HttpStatus["OK"] = 200] = "OK";\n HttpStatus[HttpStatus["NotFound"] = 404] = "NotFound";\n HttpStatus[HttpStatus["Forbidden"] = 403] = "Forbidden";\n})(HttpStatus || (HttpStatus = {}));\n\n// Das HttpStatus-Objekt sieht letztendlich so aus:\n// { \n// "200": "OK", \n// "404": "NotFound", \n// "403": "Forbidden", \n// "OK": 200, \n// "NotFound": 404, \n// "Forbidden": 403 \n// }\n\n\nSehen Sie den Trick? Der Compiler fügt sowohl Zahlen- als auch String-Schlüssel hinzu. Daher gibt Object.keys(HttpStatus) nicht nur ["OK", "NotFound", "Forbidden"] zurück, sondern auch ["200", "404", "403"]. Das zerstört die Logik unserer einfachen Lösung!
Um dies zu umgehen, müssen wir die numerischen Schlüssel herausfiltern:
\n\nfunction getEnumNameSafe(enumObj: any, value: number): string | undefined {\n const keys = Object.keys(enumObj).filter(key => isNaN(Number(key)));\n return keys.find(key => enumObj[key] === value);\n}\n\n\nAber dieser Code wirkt wie eine Krücke. Gibt es einen besseren Weg?
\n\nString-Enums: Eine andere Geschichte
\n\nWenn Sie stringbasierte Enums verwenden, wird kein Reverse Mapping erstellt. Das vereinfacht die Aufgabe:
\n\nenum Direction {\n Up = "UP",\n Down = "DOWN",\n Left = "LEFT",\n Right = "RIGHT"\n}\n\n// Object.keys(Direction) gibt nur ["Up", "Down", "Left", "Right"] zurück — perfekt!\n\n\nAber was, wenn Sie den Namen zu einem Wert benötigen? Derselbe Object.keys funktioniert hervorragend:
function getStringEn