Inicialmente, JavaScript no tenía tipificación estricta de clases y sus constructores, lo que ocasionaba errores en tiempo de ejecución. TypeScript añadió un sistema de tipos para una programación más segura y soportó la tipificación de constructores con herencia, lo cual es importante para el desarrollo de aplicaciones grandes.
La tipificación de constructores en TypeScript requiere tener en cuenta simultáneamente la firma del constructor, el tipo de la instancia creada y las características de la herencia. Los problemas surgen si las firmas de los constructores en la clase base y la clase derivada difieren, o si solo se tipa el valor de retorno y no los parámetros de entrada del constructor.
En TypeScript se pueden tipar explícitamente los constructores a través de firmas especiales, utilizando la expresión new (...args: any[]) => T. Al heredar, es importante mantener la coherencia de las firmas y ampliar correctamente las clases base.
Ejemplo de código:
class Animal { constructor(public name: string) {} } class Dog extends Animal { constructor(name: string, public breed: string) { super(name); } } // Tipo del constructor function createInstance<T>(C: new (...args: any[]) => T, ...args: any[]): T { return new C(...args); } const dog = createInstance(Dog, 'Rex', 'Labrador');
Características clave:
¿Es posible declarar varios constructores en una clase, como en Java o C#?
No, TypeScript no soporta múltiples constructores. Para simular la sobrecarga se utilizan las sobrecargas de firmas (overloads) con una única implementación. Enfoque correcto:
class Example { constructor(x: string); constructor(x: number); constructor(x: number | string) { // Una implementación } }
¿Se puede tipar solo el tipo de retorno del constructor, ignorando los parámetros?
No, la firma del constructor debe incluir obligatoriamente los parámetros. Ejemplo de una tipificación correcta:
interface Constructable<T> { new (...args: any[]): T; }
Si en la clase hija se declara un constructor sin llamar a super, ¿qué pasará?
Habrá un error de compilación: el constructor de la subclase debe llamar a super antes de acceder a this.
En el proyecto se utilizó la clase base Animal con el constructor (name), y en el heredero Dog se añadió (name, breed), pero se olvidó ampliar correctamente la firma.
Pros:
Contras:
Tipo de constructor se extrajo por separado, la fábrica createInstance se parametrizó a través de CorrectConstructable<T>, y se respetaron las firmas.
Pros:
Contras: