Molti sviluppatori sono confusi quando devono scegliere tra un’interfaccia TypeScript o un tipo. Questo probabilmente perché sono molto simili con piccole differenze.
Esploriamo alcune pratiche sensate e predefinite, mentre scopriamo alcune gemme nascoste nel linguaggio TypeScript e rispondiamo alla domanda “Dovrei usare un’interfaccia o un tipo?”
Una volta finito, controlla il mio altro articolo su TypeScript Interfaces vs Classes!
Ecco la mia regola: Per casi d’uso come la creazione di nuovi tipi attraverso cose come primitive, tipi di unione e tipi di tuple, preferisco usare la parola chiave type
. Per qualsiasi altra cosa (oggetti/array), è un interface
.
Un interface
è estremamente utile quando si ha a che fare con strutture di dati in quanto sono una rappresentazione molto visiva (anche se lo è type
, questa è tipicamente la mia preferenza). Va benissimo scegliere un type
anche per i tuoi oggetti e array.
Nonostante, scopriamo qualcosa di più su Tipi e Interfacce in TypeScript in modo da poter prendere una decisione più informata.
Oggetti: Type vs Interface
In genere definiremmo una struttura dati per modellare un tipo rispetto alle nostre variabili e argomenti di funzione. La maggior parte delle volte una struttura dati è un array o un oggetto che potrebbe contenere alcuni metodi.
Creiamo un oggetto come interfaccia (approccio raccomandato):
interface Milkshake { name: string; price: number; getIngredients(): string;}
Qui preferisco usare un’interfaccia perché è chiaro che è un’interfaccia e non una variabile con dati assegnati – una bella vittoria per la leggibilità. Usiamo name
e price
per permettere l’impostazione di record e getIngredients
come chiamata di metodo.
🎉 Scaricalo gratis!
Pronto ad andare oltre ForEach? Prendi confidenza con i metodi avanzati – Reduce, Find, Filter, Every, Some e Map.
- Comprendi appieno come gestire le strutture dati JavaScript con operazioni immutabili
- 31 pagine di sintassi profonda, esempi reali, suggerimenti e trucchi
- Scrivi una logica di programmazione più pulita e meglio strutturata in 3 ore
Come bonus extra, ti invieremo anche alcune chicche extra attraverso alcune email extra.
Quando lo confrontiamo con un tipo – potrebbe essere facilmente confuso come un oggetto reale a causa dell’assegnazione =
:
type Milkshake = { name: string; price: number; getIngredients(): string;};
Questa è solo la mia piccola preferenza per scegliere un interface
invece di usare un type
qui – ma sei libero di usare la parola chiave type
se vuoi.
Intersezione: Type vs Interface
Intersecare significa semplicemente combinare uno o più tipi! Questo schema può essere realizzato usando sia un interface
che un type
.
Immaginiamo le seguenti interfacce, vi mostrerò come possiamo intersecare un interface
e un type
:
interface MilkshakeProps { name: string; price: number;}interface MilkshakeMethods { getIngredients(): string;}
Con un’interfaccia, intersechiamo usando la parola chiave extends
. Sto usando più interfacce per mostrarvi come estendere (ereditare) in un’interfaccia finale Milkshake
contenente tutte le proprietà e i metodi definiti altrove:
// { name: string, price: number, getIngredients(): string }interface Milkshake extends MilkshakeProps, MilkshakeMethods {}
Ora possiamo usare Milkshake
ovunque vogliamo e possiamo beneficiare di avere name
, price
e getIngredients
in un solo riferimento di interfaccia.
Ecco come faremmo lo stesso con un type
e intersecando i tipi tramite &
:
// { name: string, price: number, getIngredients(): string }type Milkshake = MilkshakeProps & MilkshakeMethods;
Consiglio di usare un type
invece di un interface
quando volete intersecare dei tipi. Usare extends
sembra un po’ più prolisso e non così chiaro da leggere e sento che questo è ciò per cui la parola chiave type
è stata fatta.
È anche super facile combinare più tipi con type
. Trovo che il codice sia più chiaro che usare extends
con le interfacce.
Le interfacce sono anche limitate – l’alias type
può essere usato per tipi più complessi come tuple, primitivi, unioni e altro:
// { name: string, price: number, getIngredients(): string }type Milkshake = MilkshakeProps & { getIngredients(): string };
Primitivi: Tipo vs Interfaccia
Parliamo dei tipi primitivi. Sì, stringhe, numeri, ecc. Puoi solo assegnare un tipo primitivo ad un alias type
:
type MilkshakeName = string;interface Milkshake { name: MilkshakeName; price: number;}
Se hai bisogno di usare un primitivo, usa un type
. Le interfacce sono un no-go qui per un solo valore poiché la sintassi non lo supporta.
🎉 Scaricalo gratis!
Pronto ad andare oltre ForEach? Prendi confidenza con i metodi avanzati – Reduce, Find, Filter, Every, Some e Map.
- Comprendi appieno come gestire le strutture dati JavaScript con operazioni immutabili
- 31 pagine di sintassi profonda, esempi reali, suggerimenti e trucchi
- Scrivi una logica di programmazione più pulita e meglio strutturata in 3 ore
Come bonus extra, ti invieremo anche alcune chicche extra attraverso alcune email extra.
Per la maggior parte dei casi però, sarebbe più facile usare direttamente il valore primitivo:
interface Milkshake { name: string; price: number;}
Non complicare troppo il tuo codice!
Classi: Tipo vs Interfaccia
Che tu abbia scelto un type
o un interface
il modo in cui lo usiamo con una classe è lo stesso:
type Size = { size: string};interface Milkshake { name: string; price: number; getIngredients(): string;}class Order implements Size, Milkshake { // Size size = 'large'; // Milkshake name = 'Vanilla'; price = 399; getIngredients() { return ; }}
Le classi non supportano l’implementazione/estensione dei tipi unionali, perché sono considerate come blueprint statici. Questo significa che dovete essere super espliciti su ogni tipo che implementate, poiché non può essere dinamico o cambiare in questo momento a causa delle limitazioni di TypeScript.
Impara di più su TypeScript Interfaces vs Classes!
Functions: Tipo vs Interfaccia
In genere creerei una funzione usando l’alias type
poiché la maggior parte delle volte vorremmo digitare una funzione anonima:
type IngredientsFn = () => string;const getIngredients: IngredientsFn = () => ;
Tuttavia, se usare un interface
per questo sarebbe più nel tuo stile, ecco come fare:
interface IngredientsFn { () => string;}
Sembra un po’ strano rispetto all’uso di type
, ma entrambi sono completamente validi in TypeScript e non c’è differenza quando il codice viene compilato.
Quando non usare un Type
Ora che abbiamo esplorato i vari confronti e approcci raccomandati, è il momento di parlare del Declaration Merging, una caratteristica di TypeScript che si applica solo a interface
e sarebbe una ragione per scegliere un interface
invece di un type
.
Per unire i tipi usando type
, dovremmo fare qualcosa del genere e creare un nuovo type
finale:
type MilkshakeProps = { name: string; price: number;};type MilkshakeMethods = { getIngredients(): string;};type Milkshake = MilkshakeProps & MilkshakeMethods;
Il nostro type Milkshake
è ora un alias di tipo di MilkshakeProps
e MilkshakeMethods
. Notate che per ottenere questo comportamento abbiamo dovuto creare Milkshake
, dandoci 3 alias di tipo individuali.
Con le interfacce, c’è in effetti un approccio più intelligente (qualcuno potrebbe dire un po’ troppo intelligente) chiamato declaration merging.
Possiamo ottenere un declaration merge semplicemente dichiarando lo stesso interface
due volte nello stesso scope (questo potrebbe essere sia importando l’interfaccia da un altro modulo, sia dichiarandola localmente accanto ad un’altra interfaccia):
// declared once...interface Milkshake { name: string; price: number;}// declared again the same, it works!interface Milkshake { getIngredients(): string;}// { name: string, price: number, getIngredients(): string }const milkshake: Milkshake = { name: 'Banana', price: 399, getIngredients() {...}};
Milkshake ora contiene name
, price
e getIngredients
! Tuttavia, la fusione delle dichiarazioni è una buona cosa? Onestamente non sono un fan e sento che potrebbe portare più male che bene. Io comporrei i tuoi tipi attraverso type
piuttosto che usare la fusione delle dichiarazioni – ma almeno ora conosci le principali differenze.
Conclusione
Così ci siamo! Le principali differenze tra Tipi e Interfacce in TypeScript.
Per ricapitolare, con anche alcune preferenze personali, io rimarrei con un interface
per gli oggetti e userei la parola chiave type
alias per comporre nuovi tipi al volo. Questi nuovi tipi potrebbero anche essere da interfacce o altri tipi come tuple, unioni e tipi di intersezione. Ci sono molte possibilità, ma capendo gli approcci possiamo iniziare a scegliere lo strumento giusto.
Per la maggior parte, le interfacce e i tipi sono più o meno gli stessi, a parte qualche differenza coperta qui. Spero che vi sia piaciuto leggere!
Se siete seriamente interessati alle vostre competenze in TypeScript, il vostro prossimo passo è quello di dare un’occhiata ai miei corsi TypeScript, vi insegneranno le basi complete del linguaggio in dettaglio così come molti casi d’uso avanzati di cui avrete bisogno nello sviluppo quotidiano di TypeScript!
Buon coding!