Generici in TypeScript
Questo articolo spiega i generici in TypeScript.
YouTube Video
Generici in TypeScript
I generici in TypeScript sono una funzionalità che permette di definire funzioni, classi e interfacce riutilizzabili e sicure dal punto di vista dei tipi, parametrizzando i tipi. L'uso dei generici consente di scrivere codice che non dipende da tipi specifici, permettendo di eseguire le stesse operazioni su diversi tipi.
Nozioni di base sui Generici
I generici funzionano come modelli che accettano tipi come argomenti, permettendo a funzioni e classi di gestire diversi tipi.
Funzioni Generiche
Ecco un esempio di funzione con i tipi degli argomenti specificati usando i generici.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity<number>(42)); // 42
6console.log(identity<string>("Hello")); // Hello
T
è un argomento di tipo generico che rappresenta i tipi degli argomenti della funzione e il valore restituito. Il tipo effettivo viene determinato quando la funzione viene chiamata.- Specificando esplicitamente
<number>
o<string>
, stai specificando il tipo.
I tipi generici funzionano anche senza specificazione esplicita perché TypeScript esegue l'inferenza dei tipi.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity(42)); // 42
6console.log(identity("Hello")); // Hello
Vincoli sui Generici
Imponendo vincoli sui generici, puoi limitarli ad accettare solo tipi specifici.
1function loggingIdentity<T extends { length: number }>(arg: T): T {
2 console.log(arg.length);
3 return arg;
4}
5
6loggingIdentity("Hello"); // 5
7loggingIdentity([1, 2, 3]); // 3
8
9// loggingIdentity(42); // Error: number does not have a length property.
- Specificando
T extends { length: number }
si indica cheT
deve essere un tipo con una proprietàlength
. Pertanto, i tipi senza una proprietàlength
non saranno accettati.
Classi Generiche
Anche le classi possono essere definite usando i generici. Le classi generiche offrono tipi flessibili per proprietà e metodi.
1class Box<T> {
2 private _value: T;
3
4 constructor(value: T) {
5 this._value = value;
6 }
7
8 public getValue(): T {
9 return this._value;
10 }
11
12 public setValue(value: T): void {
13 this._value = value;
14 }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue()); // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue()); // Hello
Box<T>
dichiara il tipoT
usato all'interno della classe come generico. Ciò consente di riutilizzare la stessa classe per diversi tipi.
Interfacce Generiche
I generici possono essere utilizzati anche con le interfacce.
1interface Pair<T, U> {
2 first: T;
3 second: U;
4}
5
6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
7console.log(numberStringPair); // { first: 1, second: 'One' }
8
9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair); // { first: true, second: [ 1, 2, 3 ] }
- Specificando due tipi generici con
Pair<T, U>
, è possibile definire un oggetto con una combinazione di tipi diversi.
Argomenti di Tipo Predefiniti
È anche possibile specificare un tipo predefinito per gli argomenti di tipo generico.
1function createArray<T = string>(length: number, value: T): T[] {
2 return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a")); // ['a', 'a', 'a']
6console.log(createArray(3, 100)); // [100, 100, 100]
- Stiamo impostando l'argomento di tipo predefinito su
string
con<T = string>
. Se non viene specificato esplicitamente un tipo,T
assumerà il tipostring
.
Alias di Tipo Generico
I generics possono essere utilizzati anche come alias di tipo (type
).
1type Result<T> = {
2 success: boolean;
3 data: T;
4};
5
6const successResult: Result<number> = { success: true, data: 42 };
7const errorResult: Result<string> = { success: false, data: "Error occurred" };
8
9console.log(successResult); // { success: true, data: 42 }
10console.log(errorResult); // { success: false, data: 'Error occurred' }
Result<T>
rappresenta un oggetto risultato che contiene dati di tipoT
. In questo modo, è possibile creare alias di tipo flessibili utilizzando i generics.
Tipi Generici Multipli
Usando tipi generici multipli, è possibile definire funzioni e classi ancora più versatili.
1function merge<T, U>(obj1: T, obj2: U): T & U {
2 return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged); // { name: 'Alice', title: 'Engineer' }
- La funzione
merge
accetta due tipi diversiT
eU
e li combina per restituire un nuovo oggetto.
Riepilogo
- I generics consentono di scrivere codice riutilizzabile e sicuro trattando i tipi come parametri.
- Usando i generics in funzioni, classi e interfacce, è possibile scrivere logica flessibile che gestisce diversi tipi.
- Aggiungendo vincoli agli argomenti di tipo o impostando argomenti di tipo predefiniti, è possibile controllare l'ambito dei generics.
Usando i generics, è possibile scrivere codice indipendente dal tipo e generico, sfruttando appieno il potente sistema di tipi di TypeScript.
Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.