Inizialmente, JavaScript non aveva una tipizzazione rigorosa delle classi e dei loro costruttori, il che portava a errori durante l'esecuzione. TypeScript ha aggiunto un sistema di tipi per una programmazione più sicura e ha supportato la tipizzazione dei costruttori con ereditarietà, cosa importante per lo sviluppo di grandi applicazioni.
La tipizzazione dei costruttori in TypeScript richiede di tenere conto simultaneamente della firma del costruttore, del tipo di istanza creata e delle caratteristiche dell'ereditarietà. I problemi sorgono se le firme dei costruttori nella classe base e nella classe derivata non coincidono, o se è tipizzato solo il valore di ritorno, ma non i parametri di ingresso del costruttore.
In TypeScript, è possibile tipizzare esplicitamente i costruttori tramite firme speciali, utilizzando l'espressione new (...args: any[]) => T. Durante l'ereditarietà è importante mantenere la coerenza delle firme e estendere correttamente le classi base.
Esempio di codice:
class Animale { constructor(public name: string) {} } class Cane extends Animale { constructor(name: string, public breed: string) { super(name); } } // Tipo del costruttore function createInstance<T>(C: new (...args: any[]) => T, ...args: any[]): T { return new C(...args); } const cane = createInstance(Cane, 'Rex', 'Labrador');
Caratteristiche chiave:
È possibile dichiarare più costruttori in una classe, come in Java o C#?
No, TypeScript non supporta costruttori multipli. Per simulare il sovraccarico si utilizzano le firme di sovraccarico (overloads) con una sola implementazione. Approccio corretto:
class Esempio { constructor(x: string); constructor(x: number); constructor(x: number | string) { // Un'unica implementazione } }
È possibile tipizzare solo il tipo di ritorno del costruttore, ignorando i parametri?
No, la firma del costruttore deve includere obbligatoriamente i parametri. Esempio di tipizzazione corretta:
interface Costruibile<T> { new (...args: any[]): T; }
Cosa succede se si dichiara un costruttore in una classe figlia senza chiamare super?
Ci sarà un errore di compilazione: il costruttore della sottoclasse deve chiamare super prima di accedere a this.
Nel progetto è stata utilizzata la classe base Animale con un costruttore (name), mentre nell'erede Cane è stato aggiunto (name, breed), ma è stata dimenticata l'estensione corretta della firma.
Pro:
Contro:
Il tipo del costruttore è stato separato, la fabbrica createInstance è parametrizzata tramite CorrectConstructable<T>, le firme sono state rispettate.
Pro:
Contro: