Lezioni del modulo (2/2)
Generics Fondamentali
I Generics (programmazione generica) sono una delle caratteristiche più potenti di TypeScript. Consentono di scrivere componenti, funzioni e interfacce flessibili e riutilizzabili che possono lavorare con diversi tipi di dati, pur mantenendo la massima sicurezza dei tipi (type safety) ed evitando l'uso di any.
Le Funzioni Generiche
Pensa a un generic come a una variabile per i tipi. Consideriamo una funzione che restituisce il valore passato come argomento:
function identity<T>(arg: T): T {
return arg;
}La lettera T (abbreviazione di Type) è un segnaposto per il tipo. Quando chiamiamo identity, TypeScript cattura il tipo dell'argomento passato ed imposta automaticamente T a quel tipo:
const str = identity<string>('Hello'); // T è string
const num = identity(42); // T è number (inferito automaticamente!)Interfacce e Alias Generici
I generics possono essere applicati anche a interfacce e type alias per definire contenitori o strutture dati generiche:
interface Box<T> {
content: T;
}
const stringBox: Box<string> = { content: 'TypeScript' };
const numberBox: Box<number> = { content: 42 };Più Parametri di Tipo
Possiamo definire funzioni o tipi che utilizzano molteplici variabili di tipo (es. T e U):
function mergeObjects<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}Vincoli sui Generics (Generic Constraints)
Talvolta vogliamo limitare i tipi accettati da un generic. Possiamo usare la parola chiave extends per aggiungere un vincolo (constraint).
Ad esempio, se vogliamo che il tipo generico abbia sempre una proprietà length (come stringhe o array):
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): void {
console.log(arg.length); // Sicuro! Sappiamo che arg ha 'length'
}
logLength('Hello'); // Valido
logLength([1, 2, 3]); // Valido
// logLength(42); // Errore: number non ha la proprietà length!Prova tu
Esercizio 1: Funzione Generica Identity
Completa la funzione generica identity in modo che accetti un parametro value di tipo generico T e lo restituisca senza modifiche.
Mostra suggerimento
Il tipo di ritorno deve essere lo stesso tipo generico T del parametro.
Soluzione disponibile dopo 3 tentativi
Esercizio 2: Wrapper Generico Box
Definisci un'interfaccia generica chiamata Box che accetta un parametro di tipo T e ha una singola proprietà chiamata content di tipo T.
Mostra suggerimento
Usa la sintassi interface Box<T> { content: T; }.
Soluzione disponibile dopo 3 tentativi
Esercizio 3: Constraint Generico
Scrivi una funzione generica chiamata getLength che accetta un parametro arg. arg deve essere vincolato ad un'interfaccia che possiede una proprietà length (numero). La funzione deve restituire arg.length.
Mostra suggerimento
Dichiara la funzione come getLength<T extends HasLength>(arg: T): number e ritorna arg.length.
Soluzione disponibile dopo 3 tentativi
Esercizio 4: Coppia Generica Pair
Definisci un'interfaccia generica Pair<T, U> con due proprietà: first di tipo T e second di tipo U. Dopodiché, crea una funzione generica makePair che accetta first (di tipo T) e second (di tipo U) e restituisce un oggetto che implementa Pair<T, U>.
Mostra suggerimento
Usa la sintassi per due parametri generici Pair<T, U> e definisci makePair di conseguenza.
Soluzione disponibile dopo 3 tentativi