Początkowo JavaScript nie miał ścisłej typizacji klas i ich konstruktorów, co prowadziło do błędów w czasie wykonywania. TypeScript dodał system typów dla bezpieczniejszego programowania i wspierał typizację konstruktorów z dziedziczeniem, co jest ważne w przypadku rozwoju dużych aplikacji.
Typizacja konstruktorów w TypeScript wymaga jednoczesnego uwzględnienia sygnatury konstruktora, typu tworzonego obiektu oraz specyfiki dziedziczenia. Problemy pojawiają się, gdy sygnatury konstruktorów w klasie bazowej i pochodnej różnią się lub gdy typizowane jest tylko zwracane wartości, a nie parametry wejściowe konstruktora.
W TypeScript można wyraźnie typizować konstruktory za pomocą specjalnych sygnatur, używając wyrażenia new (...args: any[]) => T. Przy dziedziczeniu ważne jest przestrzeganie spójności sygnatur i poprawne rozszerzanie klas bazowych.
Przykład kodu:
class Animal { constructor(public name: string) {} } class Dog extends Animal { constructor(name: string, public breed: string) { super(name); } } // Typ konstruktora function createInstance<T>(C: new (...args: any[]) => T, ...args: any[]): T { return new C(...args); } const dog = createInstance(Dog, 'Rex', 'Labrador');
Kluczowe cechy:
Czy można zadeklarować w klasie kilka konstruktorów, jak w Javie lub C#?
Nie, TypeScript nie wspiera wielu konstruktorów. Aby naśladować przeciążenie, używa się przeciążenia sygnatur (overloads) z jedną implementacją. Prawidłowe podejście:
class Example { constructor(x: string); constructor(x: number); constructor(x: number | string) { // Jedna implementacja } }
Czy można typizować tylko zwracany typ konstruktora, ignorując parametry?
Nie, sygnatura konstruktora obowiązkowo zawiera parametry. Przykład poprawnej typizacji:
interface Constructable<T> { new (...args: any[]): T; }
Co się stanie, jeśli w klasie pochodnej zadeklaruje się konstruktor bez wywołania super?
Wystąpi błąd kompilacji: konstruktor podklasy musi wywołać super przed odwołaniem do this.
W projekcie użyto klasy bazowej Animal z konstruktorem (name), a w dziedziczącej klasie Dog dodano (name, breed), ale zapomniano poprawnie rozszerzyć sygnaturę.
Zalety:
Wady:
Typ konstruktora wyodrębniony osobno, fabryka createInstance parametryzowana przez CorrectConstructable<T>, sygnatury przestrzegane.
Zalety:
Wady: