TypeScript for Beginners, Part 5 Generics

Il secondo tutorial della nostra serie TypeScript for Beginners si è concentrato sui tipi di dati di base disponibili in TypeScript. Il controllo del tipo in TypeScript ci consente di assicurarci che le variabili nel nostro codice possano avere solo determinati tipi di valori assegnati. In questo modo possiamo evitare molti errori durante la scrittura del codice, perché l'IDE sarà in grado di dirci quando eseguiremo un'operazione su un tipo che non supporta. Questo rende il controllo di tipo una delle migliori caratteristiche di TypeScript.

In questo tutorial, ci concentreremo su un'altra importante caratteristica di questo linguaggio generico. Con i generici, TypeScript consente di scrivere codice che può agire su una varietà di tipi di dati anziché limitarsi a uno solo. Imparerai a conoscere il bisogno di generici in dettaglio e come è meglio che usare il qualunque tipo di dati disponibile in TypeScript.

Il bisogno di generici

Se non hai familiarità con i generici, ti starai chiedendo perché ne abbiamo bisogno. In questa sezione, risponderò a questa domanda per te. Iniziamo scrivendo una funzione che restituirà un elemento casuale da una matrice di numeri.

function randomIntElem (theArray: number []): number let randomIndex = Math.floor (Math.random () * theArray.length); restituire theArray [randomIndex];  let posizioni: numero [] = [103, 458, 472, 458]; let randomPosition: number = randomIntElem (posizioni);

Il randomElem la funzione appena definita prende come unico parametro una serie di numeri. Anche il tipo di ritorno della funzione è stato specificato come numero. Stiamo usando il Math.random () funzione per restituire un numero casuale a virgola mobile compreso tra 0 e 1. Moltiplicandolo con la lunghezza di un determinato array e chiamando Math.floor () sul risultato ci dà un indice casuale. Una volta ottenuto l'indice casuale, restituiamo l'elemento a quell'indice specifico.

Qualche tempo dopo, diciamo che è necessario ottenere un elemento stringa casuale da una serie di stringhe. A questo punto, puoi decidere di creare un'altra funzione che si rivolga in modo specifico alle stringhe.

function randomStrElem (theArray: string []): string let randomIndex = Math.floor (Math.random () * theArray.length); restituire theArray [randomIndex];  let colors: string [] = ['violet', 'indigo', 'blue', 'green']; let randomColor: string = randomStrElem (colors);

Che cosa succede se è necessario selezionare un elemento casuale da un array di un'interfaccia definita? Creare una nuova funzione ogni volta che si desidera ottenere un elemento casuale da una serie di diversi tipi di oggetti non è fattibile.

Una soluzione per questo problema è impostare il tipo di parametro dell'array passato alle funzioni come qualunque[]. In questo modo puoi scrivere la tua funzione solo una volta e funzionerà con una serie di tutti i tipi.

function randomElem (theArray: any []): any let randomIndex = Math.floor (Math.random () * theArray.length); restituire theArray [randomIndex];  let positions = [103, 458, 472, 458]; let randomPosition = randomElem (posizioni); let colors = ['violet', 'indigo', 'blue', 'green']; let randomColor = randomElem (colors);

Come puoi vedere, possiamo usare la funzione sopra per ottenere posizioni casuali e colori casuali. Uno dei principali problemi con questa soluzione è che si perderanno le informazioni sul tipo di valore che viene restituito. 

Prima eravamo sicuri randomPosition sarebbe un numero e colore casuale sarebbe una stringa Questo ci ha aiutato ad usare questi valori di conseguenza. Ora, tutto ciò che sappiamo è che l'elemento restituito potrebbe essere di qualsiasi tipo. Nel codice precedente, potremmo specificare il tipo di colore casuale essere un numero e ancora non si ottiene alcun errore.

// Questo codice verrà compilato senza errori. let colors: string [] = ['violet', 'indigo', 'blue', 'green']; let randomColor: number = randomElem (colors);

Una soluzione migliore per evitare la duplicazione del codice pur conservando le informazioni sul tipo consiste nell'utilizzare i generici. Ecco una funzione generica che restituisce elementi casuali da una matrice.

funzione randomElem(theArray: T []): T let randomIndex = Math.floor (Math.random () * theArray.length); restituire theArray [randomIndex];  let colors: string [] = ['violet', 'indigo', 'blue', 'green']; let randomColor: string = randomElem (colors);

Ora, ricevo un errore se provo a cambiare il tipo di colore casuale a partire dal stringa a numero. Ciò dimostra che l'uso di generici è molto più sicuro rispetto all'utilizzo del qualunque digitare in tali situazioni.

L'uso di Generics può sembrare molto limitante

La sezione precedente ha discusso di come è possibile utilizzare i generici anziché il qualunque digitare per scrivere una singola funzione ed evitare di sacrificare i vantaggi del controllo dei tipi. Un problema con la funzione generica che abbiamo scritto nella sezione precedente è che TypeScript non ci permetterà di eseguire molte operazioni sulle variabili passate ad esso. 

Questo perché TypeScript non può fare alcuna ipotesi sul tipo di variabile che verrà passato in anticipo alla nostra funzione generica. Di conseguenza, la nostra funzione generica può utilizzare solo quelle operazioni applicabili a tutti i tipi di dati. Il seguente esempio dovrebbe rendere questo concetto più chiaro.

function removeChar (theString: string, theChar: string): string let theRegex = new RegExp (theChar, "gi"); return theString.replace (theRegex, ");

La funzione precedente rimuoverà tutte le occorrenze del carattere specificato dalla stringa specificata. Potresti voler creare una versione generica di questa funzione in modo da poter rimuovere anche cifre specifiche da un determinato numero e caratteri da una stringa. Ecco la corrispondente funzione generica.

funzione removeIt(theInput: T, theIt: string): T let theRegex = new RegExp (theIt, "gi"); return theInput.replace (theRegex, ");

Il removeChar la funzione non ti ha mostrato un errore. Tuttavia, se si utilizza sostituire dentro rimuoverla,TypeScript te lo dirà sostituire non esiste per il tipo 'T'. Questo perché TypeScript non può più presumere che theInput sta per essere una stringa.

Questa restrizione sull'uso di metodi diversi in una funzione generica potrebbe farti pensare che il concetto di generici non sarà molto utile dopo tutto. Non c'è molto che tu possa fare con una manciata di metodi che devono essere applicabili su tutti i tipi di dati per poterli usare all'interno di una funzione generica.

Una cosa importante da ricordare a questo punto è che generalmente non è necessario creare funzioni che verranno utilizzate con tutti i tipi di dati. È più comune creare una funzione che verrà utilizzata con un set specifico o un intervallo di tipi di dati. Questo vincolo sui tipi di dati rende le funzioni generiche molto più utili.

Creare funzioni generiche mediante vincoli

Il generico rimuoverla funzione dalla sezione precedente ha mostrato un errore perché il sostituire il metodo al suo interno è pensato per essere utilizzato con le stringhe, mentre i parametri passati ad esso possono avere qualsiasi tipo di dati. 

Puoi usare il si estende parola chiave per vincolare i tipi di dati che vengono passati a una funzione generica in TypeScript. però, si estende è limitato a solo interfacce e classi. Ciò significa che la maggior parte delle funzioni generiche create conterrà parametri che estendono un'interfaccia o una classe di base. 

Ecco una funzione generica che stampa il nome di persone, familiari o celebrità passati ad essa.

interfaccia People nome: stringa interfaccia Famiglia nome: stringa, età: numero, relazione: stringa interfaccia Celebrity estende People professione: stringa funzione printName(theInput: T): void console.log ('Il mio nome è $ theInput.name');  lascia serena: Celebrity = name: 'Serena Williams', professione: 'Tennis Player' printName (serena);

Nell'esempio sopra, abbiamo definito tre interfacce e ognuna di esse ha a nome proprietà. Il generico printName la funzione che abbiamo creato accetterà qualsiasi oggetto che si estende Persone. In altre parole, è possibile passare a una funzione di famiglia o di celebrità questa funzione e stamperà il suo nome senza alcun reclamo. È possibile definire molte più interfacce e finché hanno a nome proprietà, sarete in grado di utilizzare il printName funzione senza alcun problema.

Questo è stato un esempio molto semplice, ma è possibile creare più funzioni generiche utili una volta che si è più a proprio agio con l'intero processo. Ad esempio, è possibile creare una funzione generica che calcola il valore totale di diversi articoli venduti in un determinato mese, purché ciascun elemento abbia un prezzo proprietà per memorizzare il prezzo e a venduto proprietà che memorizza il numero di articoli venduti. Usando i generici, sarai in grado di utilizzare la stessa funzione purché gli elementi estendano la stessa interfaccia o classe.

Pensieri finali

In questo tutorial, ho cercato di illustrare le basi dei generici in TypeScript in un modo facile per i principianti. Abbiamo iniziato l'articolo discutendo sulla necessità di farmaci generici. Successivamente, abbiamo appreso il modo giusto di utilizzare i generici per evitare la duplicazione del codice senza sacrificare l'abilità di controllo del tipo. Una volta comprese le nozioni di base discusse qui, puoi leggere di più sui farmaci generici nella documentazione ufficiale.

Se hai domande relative a questo tutorial, sarò lieto di risponderti nei commenti.