TypeScript - Generics: A Beginner's Guide
Ciao là, futuro supercampione del编程! Oggi ci imbarcheremo in un viaggio emozionante nel mondo dei Generics di TypeScript. Non preoccuparti se sei nuovo alla programmazione - sarò la tua guida amichevole, e lo faremo passo dopo passo. Alla fine di questo tutorial, userai i generics come un professionista!
Cos'è un Generic e Perché Dovremmo Preoccuparcene?
Prima di immergerci nei dettagli, iniziamo con una semplice analogia. Immagina di avere una scatola magica che può contenere qualsiasi tipo di oggetto. A volte ci metti un libro, altre volte un giocattolo, o anche un panino. Questo è essenzialmente ciò che sono i generics in TypeScript - ci permettono di creare codice flessibile e riutilizzabile che può funzionare con diversi tipi.
Esempi di Problemi
Analizziamo alcuni scenari in cui i generics possono salvare la situazione:
- Vuoi creare una funzione che può invertire qualsiasi tipo di array (numeri, stringhe, oggetti).
- Hai bisogno di una classe che può memorizzare e recuperare qualsiasi tipo di dati.
- Stai costruendo una funzione utility che dovrebbe funzionare con vari tipi di dati.
Senza generics, dovresti scrivere funzioni o classi separate per ogni tipo di dati. Questo significa molta ripetizione, e come ogni buon programmatore sa, la ripetizione è il nemico del codice pulito!
TypeScript Generics inUnser soccorso!
Ora, mettiamo le mani al lavoro e vediamo come funzionano i generics in azione.
Funzione Generica di Base
Ecco una semplice funzione generica che può funzionare con qualsiasi tipo:
function identity<T>(arg: T): T {
return arg;
}
Analizziamo questa funzione:
-
<T>
è il nostro parametro di tipo. È come un placeholder per il tipo che useremo. -
(arg: T)
significa che la nostra funzione accetta un argomento di tipo T. -
: T
dopo le parentesi significa che la nostra funzione restituirà un valore di tipo T.
Possiamo usare questa funzione così:
let output1 = identity<string>("Ciao, Generics!");
let output2 = identity<number>(42);
console.log(output1); // "Ciao, Generics!"
console.log(output2); // 42
Bello, vero? La stessa funzione funziona con diversi tipi!
Interfaccia Generica
Possiamo anche usare generics con le interfacce. Ecco un esempio:
interface GenericBox<T> {
contents: T;
}
let stringBox: GenericBox<string> = { contents: "Un messaggio segreto" };
let numberBox: GenericBox<number> = { contents: 123 };
console.log(stringBox.contents); // "Un messaggio segreto"
console.log(numberBox.contents); // 123
Il nostro GenericBox
può contenere qualsiasi tipo di contenuto. È come quella scatola magica di cui parlavamo prima!
Classi Generiche
Creiamo una classe generica che può funzionare come un semplice data store:
class DataStore<T> {
private data: T[] = [];
addItem(item: T): void {
this.data.push(item);
}
getItems(): T[] {
return this.data;
}
}
let stringStore = new DataStore<string>();
stringStore.addItem("Ciao");
stringStore.addItem("Mondo");
console.log(stringStore.getItems()); // ["Ciao", "Mondo"]
let numberStore = new DataStore<number>();
numberStore.addItem(1);
numberStore.addItem(2);
console.log(numberStore.getItems()); // [1, 2]
Questa classe DataStore
può memorizzare e recuperare qualsiasi tipo di dati. Molto comodo, vero?
vincoli di Generic
A volte, vogliamo limitare i tipi che possono essere utilizzati con i nostri generics. Possiamo farlo con i vincoli:
interface Lengthy {
length: number;
}
function logLength<T extends Lengthy>(arg: T): void {
console.log(arg.length);
}
logLength("Ciao"); // 5
logLength([1, 2, 3]); // 3
logLength({ length: 10 }); // 10
// logLength(123); // Errore: Number non ha una proprietà length
Qui, la nostra funzione logLength
può funzionare solo con tipi che hanno una proprietà length
.
Vantaggi dei Generics
Ora che abbiamo visto i generics in azione, riassumiamo i loro vantaggi:
- Riutilizzo del Codice: Scrivi una volta, usa con molti tipi.
- Sicurezza del Tipo: Cattura errori relativi ai tipi durante la compilation.
- Flessibilità: Crea componenti che possono funzionare con una varietà di tipi di dati.
- Chiarezza: Rende chiare le relazioni tra input e output.
Tabella dei Metodi Generici
Ecco una tabella utile di alcuni metodi generici che potresti incontrare:
Metodo | Descrizione | Esempio |
---|---|---|
Array.map<U>() |
Trasforma gli elementi dell'array | [1, 2, 3].map<string>(n => n.toString()) |
Promise.all<T>() |
Aspetta che tutte le promise siano risolte | Promise.all<number>([Promise.resolve(1), Promise.resolve(2)]) |
Object.keys<T>() |
Ottiene le chiavi dell'oggetto come array | Object.keys<{name: string}>({name: "Alice"}) |
JSON.parse<T>() |
Parsea una stringa JSON in un oggetto | JSON.parse<{age: number}>('{"age": 30}') |
Conclusione
Complimenti! Hai appena fatto i tuoi primi passi nel meraviglioso mondo dei generics di TypeScript. Ricorda, come ogni strumento potente, i generics possono sembrare un po' complicati all'inizio, ma con la pratica diventeranno second nature.
Mentre continui il tuo viaggio di programmazione, scoprirai che i generics sono come un coltello svizzero nel tuo set di strumenti TypeScript - versatile, potente e incredibilmente utile. Quindi vai avanti e programma, giovane padawan, e che i generics siano con te!
Buon coding, e fino alla prossima volta, continua a esplorare e imparare!
Credits: Image by storyset