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!

TypeScript - Generics

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:

  1. Vuoi creare una funzione che può invertire qualsiasi tipo di array (numeri, stringhe, oggetti).
  2. Hai bisogno di una classe che può memorizzare e recuperare qualsiasi tipo di dati.
  3. 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:

  1. Riutilizzo del Codice: Scrivi una volta, usa con molti tipi.
  2. Sicurezza del Tipo: Cattura errori relativi ai tipi durante la compilation.
  3. Flessibilità: Crea componenti che possono funzionare con una varietà di tipi di dati.
  4. 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