[Medium] Generics
1. Cosa sono i generics?
Quale problema risolvono i generics in TypeScript?
I generics ti permettono di scrivere codice riutilizzabile e type-safe senza codificare un tipo concreto specifico.
Senza i generics, spesso duplichi le funzioni per ogni tipo. Con i generics, una singola implementazione può funzionare per molti tipi mantenendo le informazioni sui tipi.
2. Funzioni generiche (Generic functions)
Sintassi di base
function identity<T>(value: T): T {
return value;
}
const n = identity<number>(123);
const s = identity('hello'); // il tipo viene inferito come string
Helper generico per array
function firstItem<T>(items: T[]): T | undefined {
return items[0];
}
const firstNumber = firstItem([1, 2, 3]);
const firstString = firstItem(['a', 'b']);
3. Vincoli generici (Generic constraints)
A volte hai bisogno di un tipo generico con campi obbligatori.
function getLength<T extends { length: number }>(value: T): number {
return value.length;
}
getLength('TypeScript');
getLength([1, 2, 3]);
// getLength(123); // Errore: number non ha length
extends qui significa "deve soddisfare questa struttura".
4. Parametri di tipo multipli (Multiple type parameters)
function toPair<K, V>(key: K, value: V): [K, V] {
return [key, value];
}
const pair = toPair('id', 1001); // [string, number]
Questo è comune nelle mappe, nei dizionari e nelle utility di trasformazione dei dati.
5. Interfacce e alias di tipo generici
Interfaccia generica (Generic interface)
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
}
const userResponse: ApiResponse<{ id: number; name: string }> = {
success: true,
data: { id: 1, name: 'Pitt' },
};
Alias di tipo generico (Generic type alias)
type Result<T> =
| { ok: true; value: T }
| { ok: false; message: string };
6. Classi generiche (Generic classes)
class Queue<T> {
private items: T[] = [];
enqueue(item: T): void {
this.items.push(item);
}
dequeue(): T | undefined {
return this.items.shift();
}
}
const numberQueue = new Queue<number>();
numberQueue.enqueue(10);
7. Tipi generici predefiniti (Default generic types)
Puoi definire tipi di fallback.
type ApiResult<T = string> = {
data: T;
status: number;
};
const a: ApiResult = { data: 'ok', status: 200 };
const b: ApiResult<number> = { data: 1, status: 200 };
8. keyof con i generics
function pick<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { id: 1, name: 'Alex' };
const name = pick(user, 'name'); // string
Questo pattern è fondamentale per molti tipi utility.
9. Errori comuni e best practice
Errori comuni
- Usare troppi parametri generici senza uno scopo chiaro
- Nominare tutto
Tnelle API complesse - Ricorrere a
anyinvece di vincoli appropriati
Best practice
- Usa nomi descrittivi nei casi complessi (
TItem,TValue) - Aggiungi vincoli dove il comportamento dipende dalla struttura
- Preferisci l'inferenza prima, argomenti di tipo espliciti solo quando necessario
- Mantieni le API generiche piccole e focalizzate
10. Risposte rapide per i colloqui (Quick Interview Answers)
D1: Qual è il più grande beneficio dei generics?
Codice riutilizzabile con sicurezza dei tipi in fase di compilazione.
D2: Cosa significa T extends U?
T deve essere assegnabile a U; è un vincolo generico.
D3: Quando dovrei evitare i generics?
Quando l'astrazione non migliora la chiarezza o supporta solo un tipo concreto.