Wer bist du, Objekt? Den Klassennamen in TypeScript zur Laufzeit ermitteln

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 könnte der Klassenname zur Laufzeit nützlich sein?

\n\n

Stellen Sie sich vor: Sie schreiben ein komplexes System in TypeScript. Sie haben eine Klassenhierarchie — User, Admin, Moderator. Irgendwo tief im Code erhalten Sie ein Objekt, wissen aber nicht, was es wirklich ist. In der Konsole sehen Sie nur object.

\n\n

Oder Sie bauen einen Logger, der nicht nur [Object], sondern einen aussagekräftigen Klassennamen ausgeben soll: [User: John]. Oder Sie schreiben einen Decorator, der je nach Typ des Objekts entscheiden soll, wie es verarbeitet wird.

\n\n

Genau hier kommt die Frage mit tausend Aufrufen auf Stack Overflow ins Spiel: "Get an object's class name at runtime". Heute geben wir nicht nur eine Antwort, sondern schauen unter die Haube von TypeScript und JavaScript, um zu verstehen, wie das wirklich funktioniert.

\n\n

Ja, TypeScript ist ein Overlay über JavaScript. Die ganze Magie der Typen verschwindet nach der Kompilierung. Aber der Klassenname ist kein Typ, sondern eine Eigenschaft des Prototyps. Und er bleibt uns zur Laufzeit erhalten.

\n\n

Der einfachste Weg: constructor.name

\n\n

Wenn Sie jemals nach dieser Frage gegoogelt haben, haben Sie sicher diesen Einzeiler gesehen:

\n\n
class User {\n  constructor(public name: string) {}\n}\n\nconst user = new User("Alice");\nconsole.log(user.constructor.name); // "User"
\n\n

Funktioniert es? Ja. Schnell? Ja. Aber es gibt Nuancen, die Sie beißen können, wenn Sie nicht wissen, wie es funktioniert.

\n\n

Wie funktioniert das unter der Haube?

\n\n

Jedes Objekt in JavaScript hat eine Eigenschaft constructor. Dies ist ein Verweis auf die Funktion, die das Objekt erstellt hat. Und jede Funktion (eine Klasse ist auch eine Funktion) hat eine Eigenschaft name.

\n\n

Wenn Sie user.constructor.name schreiben, macht die Engine Folgendes:

\n
    \n
  • Sie geht die Prototypenkette des Objekts user entlang.
  • \n
  • Sie findet die Eigenschaft constructor auf User.prototype.
  • \n
  • Sie liest name der Konstruktorfunktion User.
  • \n
\n\n

Dies ist eine günstige Operation, aber nicht kostenlos. In den meisten Fällen werden Sie es nicht einmal bemerken.

\n\n

Wann funktioniert constructor.name nicht?

\n\n

Hier ist ein klassischer Fallstrick:

\n\n
const obj = Object.create(null);\nconsole.log(obj.constructor); // undefined\n// console.log(obj.constructor.name); // TypeError!
\n\n

Ein Objekt, das mit Object.create(null) erstellt wurde, hat keinen Prototypen. Es hat kein constructor. Seien Sie vorsichtig.

\n\n

Der zweite Fall ist die Minifizierung. Wenn Sie einen Bundler (Webpack, Terser) verwenden, der Klassen umbenennt, kann constructor.name etwas wie t oder e zurückgeben. Dies ist nur ein Problem für die Produktion, aber man sollte es wissen.

\n\n

Alternative: instanceof und benutzerdefinierte Prüfungen

\n\n

Manchmal brauchen Sie nicht nur den Namen, sondern eine Prüfung: "Ist dieses Objekt eine Instanz der Klasse X?"

\n\n
class Animal {}\nclass Dog extends Animal {}\n\nconst dog = new Dog();\n\nconsole.log(dog instanceof Dog);    // true\nconsole.log(dog instanceof Animal); // true\nconsole.log(dog instanceof Object); // true
\n\n

instanceof funktioniert über die Prototypenkette. Es prüft, ob Dog.prototype in der Prototypenkette des Objekts dog vorhanden ist. Wenn ja — true.

\n\n

Aber instanceof liefert Ihnen keinen String mit dem Namen. Es liefert einen Boolean-Wert. Für Logs oder Serialisierung ist das nicht geeignet.

\n\n

Kombinieren: Prüfung + Name

\n\n

Sie können ein Utility schreiben, das zuerst den Typ prüft und dann den Namen zurückgibt:

\n\n
function getClassName(obj: any): string | null {\n  if (obj === null || obj === undefined) return null;\n  if (typeof obj !== 'object' && typeof obj !== 'function') return null;\n\n  // Schutz vor Object.create(null)\n  if (!obj.constructor) return 'Object (no prototype)';\n\n  const name                

Blogs

Buchempfehlungen