Ursprünglich hatte JavaScript keine strenge Typisierung von Klassen und deren Konstruktoren, was zu Laufzeitfehlern führte. TypeScript führte ein Typsystem für sichereres Programmieren ein und unterstützte die Typisierung von Konstruktoren mit Vererbung, was für die Entwicklung großer Anwendungen wichtig ist.
Die Typisierung von Konstruktoren in TypeScript erfordert die gleichzeitige Berücksichtigung der Konstruktor-Signatur, des Typs der erstellten Instanz und der Besonderheiten der Vererbung. Probleme treten auf, wenn sich die Signaturen der Konstruktoren in der Basisklasse und der abgeleiteten Klasse unterscheiden oder wenn nur der Rückgabewert und nicht die Eingabewerte des Konstruktors typisiert sind.
In TypeScript können Konstruktoren durch spezielle Signaturen explizit typisiert werden, indem der Ausdruck new (...args: any[]) => T verwendet wird. Bei der Vererbung ist es wichtig, die Konsistenz der Signaturen zu wahren und die Basisklassen korrekt zu erweitern.
Beispielcode:
class Animal { constructor(public name: string) {} } class Dog extends Animal { constructor(name: string, public breed: string) { super(name); } } // Konstruktor-Typ function createInstance<T>(C: new (...args: any[]) => T, ...args: any[]): T { return new C(...args); } const dog = createInstance(Dog, 'Rex', 'Labrador');
Wesentliche Merkmale:
Kann man in einer Klasse mehrere Konstruktoren wie in Java oder C# deklarieren?
Nein, TypeScript unterstützt keine mehrfachen Konstruktoren. Um Überladungen zu simulieren, verwendet man Überladungen von Signaturen (Overloads) mit einer Implementierung. Der richtige Ansatz:
class Example { constructor(x: string); constructor(x: number); constructor(x: number | string) { // Eine Implementierung } }
Kann man nur den Rückgabetyp des Konstruktors typisieren und die Parameter ignorieren?
Nein, die Signatur des Konstruktors muss unbedingt Parameter enthalten. Beispiel für eine korrekte Typisierung:
interface Constructable<T> { new (...args: any[]): T; }
Was passiert, wenn im abgeleiteten Klassenn den Konstruktor ohne super aufruft?
Es wird ein Kompilierungsfehler auftreten: Der Konstruktor der Unterklasse muss super aufrufen, bevor er auf this zugreift.
Im Projekt wurde die Basisklasse Animal mit dem Konstruktor (name) verwendet, und im Erben Dog wurden (name, breed) hinzugefügt, aber die Signatur wurde nicht korrekt erweitert.
Vorteile:
Nachteile:
Der Typ des Konstruktors wurde separat ausgearbeitet, die Fabrik createInstance ist parametrisiert mit CorrectConstructable<T>, die Signaturen wurden eingehalten.
Vorteile:
Nachteile: