TypeScript Advanced Generics spiegato con esempi
I generici in TypeScript forniscono un modo per creare componenti di codice riutilizzabili e flessibili lavorando con una varietà di tipi di dati. I generici avanzati sviluppano ulteriormente questo concetto introducendo funzionalità aggiuntive come vincoli, valori predefiniti e tipi multipli, che consentono agli sviluppatori di scrivere codice più robusto e sicuro per i tipi. In questo articolo, verranno utilizzati esempi per esplorare questi concetti avanzati nei generici.
Vincoli generici
I vincoli limitano i tipi che un generico può accettare. Ciò assicura che il tipo passato a una funzione o classe generica soddisfi determinati criteri. Ad esempio, un vincolo può essere utilizzato per garantire che il tipo generico abbia una proprietà o un metodo specifici.
function getLength<T extends { length: number }>(arg: T): number {
return arg.length;
}
const stringLength = getLength("TypeScript");
const arrayLength = getLength([1, 2, 3]);
In questo esempio, il vincolo <T extends { length: number }>
garantisce che l'argomento passato a getLength
abbia una proprietà length
.
Generici multipli
TypeScript consente l'uso di più tipi generici nella stessa funzione, classe o interfaccia. Ciò è utile quando si lavora con coppie di valori o altre strutture dati che coinvolgono più tipi.
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
const stringNumberPair = pair("TypeScript", 2024);
Questa funzione, pair
, accetta due diversi tipi generici, T
e U
, e restituisce una tupla contenente entrambi i tipi.
Tipi generici predefiniti
I generici in TypeScript possono anche avere tipi predefiniti. Ciò è utile quando si desidera che un generico abbia un tipo di fallback se non viene fornito alcun tipo specifico.
function identity<T = string>(value: T): T {
return value;
}
const defaultString = identity("Hello"); // T is string
const customNumber = identity<number>(100); // T is number
In questo esempio, se non viene passato alcun tipo a identity
, il valore predefinito è string
.
Utilizzo di generici con interfacce
I generici possono essere usati con le interfacce per definire strutture complesse in cui i tipi non sono fissi. Ciò aggiunge flessibilità al modo in cui i dati vengono gestiti.
interface Container<T> {
value: T;
}
const stringContainer: Container<string> = { value: "Hello" };
const numberContainer: Container<number> = { value: 42 };
L'interfaccia Container
è progettata per contenere un valore di qualsiasi tipo, consentendo diversi tipi di contenitori con tipi specifici.
Classi generiche
Le classi in TypeScript possono anche essere generiche. Ciò è particolarmente utile quando si progettano classi che funzionano con vari tipi di dati, come classi di archiviazione dati o di raccolta.
class DataStore<T> {
private data: T[] = [];
add(item: T): void {
this.data.push(item);
}
getAll(): T[] {
return this.data;
}
}
const stringStore = new DataStore<string>();
stringStore.add("Hello");
stringStore.add("TypeScript");
const numberStore = new DataStore<number>();
numberStore.add(42);
In questo esempio, la classe DataStore
funziona con qualsiasi tipo di dati, fornendo un modo sicuro per archiviare e recuperare elementi.
Conclusione
I generici avanzati in TypeScript sono uno strumento potente per scrivere codice flessibile, riutilizzabile e sicuro per i tipi. Utilizzando vincoli, tipi multipli, valori predefiniti e generici in classi e interfacce, gli sviluppatori possono scrivere codice più complesso e robusto. La comprensione e l'utilizzo di questi concetti avanzati consente una maggiore flessibilità e garantisce la sicurezza dei tipi in tutte le applicazioni.