TypeScript per principianti, parte 3 interfacce

Abbiamo iniziato questa serie con un tutorial introduttivo che ti ha introdotto a diverse funzionalità di TypeScript. Ti ha anche insegnato come installare TypeScript e suggerito alcuni IDE che puoi usare per scrivere e compilare il tuo codice TypeScript. 

Nel secondo tutorial, abbiamo trattato diversi tipi di dati disponibili in TypeScript e il loro utilizzo può aiutarti a evitare molti errori. Assegnare un tipo di dati come a stringa a una variabile specifica dice a TypeScript che si desidera assegnare solo una stringa. Basandosi su queste informazioni, TypeScript può indicarcelo in un secondo momento quando si tenta di eseguire un'operazione che non dovrebbe essere eseguita su stringhe.

In questo tutorial, imparerai a conoscere le interfacce in TypeScript. Con le interfacce, puoi fare un ulteriore passo avanti e definire la struttura o il tipo di oggetti più complessi nel tuo codice. Proprio come i semplici tipi di variabili, questi oggetti dovranno anche seguire una serie di regole create da te. Questo può aiutarti a scrivere codice più confidenzialmente, con meno possibilità di errore.

Creare la nostra prima interfaccia

Supponiamo che tu abbia un oggetto lago nel tuo codice e lo usi per memorizzare informazioni su alcuni dei più grandi laghi per area geografica. Questo oggetto del lago avrà proprietà come il nome del lago, la sua area, lunghezza, profondità e i paesi in cui quel lago esiste.

I nomi dei laghi verranno memorizzati come una stringa. Le lunghezze di questi laghi saranno espresse in chilometri e le aree saranno in chilometri quadrati, ma entrambe queste proprietà verranno memorizzate come numeri. Le profondità dei laghi saranno in metri, e questo potrebbe anche essere un galleggiante. 

Poiché tutti questi laghi sono molto grandi, le loro spiagge non sono generalmente limitate a un singolo paese. Useremo una serie di stringhe per memorizzare i nomi di tutti i paesi sulla battigia di un determinato lago. Un booleano può essere usato per specificare se il lago è acqua salata o acqua dolce. Il seguente frammento di codice crea un'interfaccia per il nostro oggetto lago.

interfaccia Laghi nome: stringa, area: numero, lunghezza: numero, profondità: numero, isFreshwater: boolean, countries: string []

Il Laghi l'interfaccia contiene il tipo di ciascuna proprietà che useremo durante la creazione dei nostri oggetti lago. Se ora provi ad assegnare diversi tipi di valori a una di queste proprietà, riceverai un errore. Ecco un esempio che memorizza informazioni sul nostro primo lago.

let firstLake: Lakes = name: 'Caspian Sea', lunghezza: 1199, profondità: 1025, area: 371000, isFreshwater: false, paesi: ['Kazakhstan', 'Russia', 'Turkmenistan', 'Azerbaijan', 'Iran ']

Come puoi vedere, l'ordine in cui assegni un valore a queste proprietà non ha importanza. Tuttavia, non puoi omettere un valore. Dovrai assegnare un valore a ogni proprietà per evitare errori durante la compilazione del codice. 

In questo modo, TypeScript si assicura di non aver perso nessuno dei valori richiesti per errore. Ecco un esempio in cui ci siamo dimenticati di assegnare il valore di profondità proprietà per un lago.

let secondLake: Lakes = name: 'Superior', lunghezza: 616, area: 82100, isFreshwater: true, countries: ['Canada', 'United States']

Lo screenshot qui sotto mostra il messaggio di errore in Visual Studio Code dopo che ci siamo dimenticati di specificare il profondità. Come puoi vedere, l'errore indica chiaramente che ci manca il profondità proprietà per il nostro oggetto lago.

Rendere le proprietà dell'interfaccia opzionali

A volte, potresti aver bisogno di una proprietà solo per alcuni oggetti specifici. Ad esempio, supponiamo di voler aggiungere una proprietà per specificare i mesi in cui un lago è ghiacciato. Se si aggiunge la proprietà direttamente all'interfaccia, come abbiamo fatto fino ad ora, si otterrà un errore per altri laghi che non si bloccano e quindi non hanno congelato proprietà. Allo stesso modo, se si aggiunge la proprietà ai laghi che sono congelati ma non nella dichiarazione dell'interfaccia, si otterrà comunque un errore.

In questi casi, puoi aggiungere un punto interrogativo (?) dopo il nome di una proprietà per impostarlo come facoltativo nella dichiarazione dell'interfaccia. In questo modo, non riceverai un errore per proprietà mancanti o proprietà sconosciute. L'esempio seguente dovrebbe essere chiaro.

interfaccia Laghi nome: stringa, area: numero, lunghezza: numero, profondità: numero, isFreshwater: booleano, paesi: stringa [], congelato ?: stringa [] let secondLake: Laghi = nome: 'Superiore', profondità: 406.3, lunghezza: 616, area: 82100, isFreshwater: true, paesi: ['Canada', 'Stati Uniti'] let thirdLake: Lakes = nome: 'Baikal', profondità: 1637, lunghezza: 636, area: 31500 , isFreshwater: true, countries: ['Russia'], congelato: ['January', 'February', 'March', 'April', 'May']

Utilizzo delle firme dell'indice

Le proprietà facoltative sono utili quando alcuni dei tuoi oggetti le useranno. Tuttavia, cosa accadrebbe se ogni lago avesse anche un proprio insieme unico di proprietà come attività economiche, la popolazione di diversi tipi di flora e fauna fiorente in quel lago, o gli insediamenti intorno al lago? Aggiungere così tante proprietà diverse all'interno della dichiarazione dell'interfaccia stessa e renderle opzionali non è l'ideale.

Come soluzione, TypeScript consente di aggiungere proprietà aggiuntive a oggetti specifici con l'aiuto delle firme dell'indice. L'aggiunta di una firma dell'indice alla dichiarazione dell'interfaccia consente di specificare qualsiasi numero di proprietà per diversi oggetti che si stanno creando. È necessario apportare le seguenti modifiche all'interfaccia. 

In questo esempio, ho utilizzato una firma di indice per aggiungere informazioni su diversi insediamenti intorno ai laghi. Poiché ogni lago avrà i propri insediamenti, l'uso di proprietà facoltative non sarebbe stata una buona idea.

interfaccia Laghi nome: stringa, area: numero, lunghezza: numero, profondità: numero, isFreshwater: boolean, countries: string [], frozen ?: string [], [extraProp: string]: any let fourthLake: Lakes =  nome: 'Tanganica', profondità: 1470, lunghezza: 676, area: 32600, isFreshwater: true, paesi: ['Burundi', 'Tanzania', 'Zambia', 'Congo'], kigoma: 'Tanzania', kalemie: 'Congo', bujumbura: 'Burundi'

Come altro esempio, diciamo che stai creando un gioco con diversi tipi di nemici. Tutti questi nemici avranno alcune proprietà comuni come le loro dimensioni e la loro salute. Queste proprietà possono essere incluse direttamente nella dichiarazione dell'interfaccia. Se ciascuna categoria di questi nemici ha un unico set di armi, quelle armi possono essere incluse con l'aiuto di una firma indice.

Proprietà di sola lettura

Quando si lavora con oggetti diversi, potrebbe essere necessario lavorare con proprietà che dovrebbero essere modificate solo quando creiamo per la prima volta l'oggetto. È possibile contrassegnare queste proprietà come sola lettura nella dichiarazione dell'interfaccia. Questo è simile all'utilizzo del const parola chiave, ma const dovrebbe essere usato con variabili, mentre sola lettura è pensato per le proprietà.

TypeScript ti consente anche di creare array di sola lettura usando ReadonlyArray. La creazione di un array di sola lettura comporterà la rimozione di tutti i metodi di muting da esso. Questo è fatto per assicurarti che non puoi cambiare il valore dei singoli elementi in seguito. Ecco un esempio di utilizzo di proprietà e matrici di sola lettura nelle dichiarazioni dell'interfaccia.

Interfaccia Nemico dimensione readonly: numero, salute: numero, intervallo: numero, danno di sola lettura: numero let tank: Enemy = dimensione: 50, health: 100, range: 60, damage: 12 // Questo è Okay tank. salute = 95; // Errore perché 'damage' è di sola lettura. tank.damage = 10;

Funzioni e interfacce

È anche possibile utilizzare le interfacce per descrivere un tipo di funzione. Ciò richiede che tu dia alla funzione una firma di chiamata con il suo elenco di parametri e il tipo di ritorno. È inoltre necessario fornire sia un nome che un tipo per ciascuno dei parametri. Ecco un esempio:

interfaccia EnemyHit (nome: nemico, damageDone: numero): numero;  let tankHit: EnemyHit = function (tankName: Enemy, damageDone: number) tankName.health - = damageDone; return tankName.health; 

Nel codice precedente, abbiamo dichiarato un'interfaccia di funzione e l'abbiamo usata per definire una funzione che sottrae il danno inflitto a un serbatoio dalla sua salute. Come puoi vedere, non è necessario utilizzare lo stesso nome per i parametri nella dichiarazione dell'interfaccia e la definizione del codice affinché funzioni.

Pensieri finali

Questo tutorial ti ha presentato le interfacce e come puoi usarle per assicurarti di scrivere codice più robusto. Ora dovresti essere in grado di creare le tue interfacce con proprietà opzionali e di sola lettura. 

Hai anche imparato a utilizzare le firme dell'indice per aggiungere una varietà di altre proprietà a un oggetto che non è incluso nella dichiarazione dell'interfaccia. Questo tutorial intendeva iniziare con le interfacce in TypeScript e puoi leggere ulteriori informazioni su questo argomento nella documentazione ufficiale.

Nel prossimo tutorial, imparerai a conoscere le classi in TypeScript. Se hai domande relative alle interfacce, fammelo sapere nei commenti.