Menu

Classi astratte in TypeScript: metodi, proprietà e interfacce

Una classe astratta in TypeScript è una classe base che non si può istanziare e che può lasciare dei metodi da implementare alle sottoclassi. Scopri metodi e proprietà astratti, il pattern template method, i tipi di costruttore astratti e quando conviene di più un'interfaccia.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Una classe astratta è una classe base marcata abstract. Non si può creare con new e può dichiarare metodi abstract senza corpo, che ogni sottoclasse deve implementare.

Shape condivide describe() con ogni sottoclasse e obbliga ciascuna a fornire area(). Il tipo Shape[] contiene qualsiasi mix di sottoclassi.

Una classe astratta non si può istanziare

Chiamare new su una classe astratta è un errore di compilazione, perché l'oggetto avrebbe metodi senza implementazione:

index.ts(6,11): error TS2511: Cannot create an instance of an abstract class.

È una regola di compilazione. abstract sparisce dall'output, quindi la Shape emessa è una normale classe JavaScript e del codice JavaScript non tipizzato potrebbe comunque chiamare new Shape(). Quando una libreria ha bisogno di una protezione a runtime, il costruttore può controllare new.target:

Metodi e proprietà astratti

Una sottoclasse deve implementare ogni membro astratto, oppure essere astratta a sua volta. Dimenticarne uno è l'errore TS2515, che suona come Non-abstract class 'Square' does not implement inherited abstract member area from class 'Shape', oppure TS2654, che li elenca tutti quando ne mancano diversi.

Campi, getter e metodi possono essere tutti astratti, e possono essere protected:

Un metodo astratto non ha corpo; scriverne uno è l'errore TS1245 (Method 'x' cannot have an implementation because it is marked abstract). Una classe astratta non deve per forza avere membri astratti: abstract da solo impedisce semplicemente l'istanziazione diretta.

Il pattern template method

È il motivo più comune per scrivere una classe astratta: la classe base fissa l'ordine dei passaggi e ogni sottoclasse riempie i passaggi che cambiano.

Le classi astratte possono essere generiche, come qui, così ogni sottoclasse sceglie il tipo di record.

Tipi di costruttore astratti

Per una classe astratta, typeof Shape è un costruttore che non puoi chiamare, quindi un parametro tipizzato typeof Shape non può fare new c(). Quando una funzione deve accettare classi astratte (per esempio per registrarle o controllare instanceof), tipizzala con una firma di costruzione astratta:

abstract new accetta sia classi astratte sia concrete; new da solo accetta solo quelle concrete.

Classe astratta vs interfaccia

Classe astrattaInterfaccia
Contiene codicesì: metodi, inizializzatori dei campi, costruttoreno, solo tipi
Esiste a runtimesìno, viene cancellata
instanceoffunzionanon è possibile
Una classe può usarneuna (extends)molte (implements)
Modificatori di accessoprivate, protected, publicsolo membri pubblici
Tipo per oggetti semplicisolo se non ha membri private/protected, e allora instanceof falliscesì, qualsiasi valore con quella forma

La regola pratica: un'interfaccia quando devi solo descrivere una forma (il caso più comune, e funziona anche con gli oggetti letterali), una classe astratta quando le sottoclassi condividono un'implementazione reale e vuoi che il compilatore le obblighi a riempire i vuoti. Le due si combinano bene: un'interfaccia per il contratto pubblico, una classe astratta come base comoda che la implementa. Vedi interfacce vs tipi per l'altro confronto frequente.

Errori comuni

  • Usare una classe astratta dove basterebbe un'interfaccia. Se la classe base non contiene codice, è un'interfaccia con peso extra a runtime e il limite dell'ereditarietà singola.
  • Provare static abstract. Non è consentito. I membri statici non possono essere astratti.
  • Aspettarsi un errore a runtime da new su una classe astratta. Non c'è, a meno che tu non scriva il controllo su new.target.
  • Chiamare un metodo astratto dal costruttore della classe base. Viene eseguito prima che i campi della sottoclasse siano inizializzati, quindi l'implementazione li vede come undefined.

Domande frequenti

Che cos'è una classe astratta in TypeScript?

Una classe marcata abstract che non si può creare con new e che può dichiarare membri abstract senza implementazione. Le sottoclassi devono implementare ogni membro astratto. È un modo per condividere codice e imporre una forma allo stesso tempo.

Che differenza c'è tra una classe astratta e un'interfaccia in TypeScript?

Una classe astratta può contenere codice vero (metodi implementati, campi con valori iniziali, un costruttore) ed esiste a runtime, quindi instanceof funziona con lei; una classe può estenderne solo una. Un'interfaccia non contiene codice, viene cancellata in compilazione e una classe può implementarne molte. Usa una classe astratta per condividere comportamento, un'interfaccia per descrivere una forma.

Una classe astratta può avere un costruttore in TypeScript?

Sì. Viene eseguito quando una sottoclasse chiama super(...). Resta comunque impossibile chiamare new sulla classe astratta stessa (TS2511: Cannot create an instance of an abstract class).

I metodi statici possono essere astratti in TypeScript?

No. abstract vale solo per i membri di istanza; static abstract è l'errore TS1243 ('static' modifier cannot be used with 'abstract' modifier). Per imporre una forma statica, tipizza il costruttore con un'interfaccia che includa il membro statico e verifica la classe rispetto a quella.

Una classe astratta viene imposta a runtime?

No. abstract viene cancellato, quindi la classe compilata è JavaScript normale e del semplice codice JavaScript potrebbe comunque chiamare new su di essa. Se è importante, controlla new.target nel costruttore e lancia un errore.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA