Vai al contenuto
eLearner.app
Modulo 3 · Lezione 2 di 26/14 nel corso~15 min
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:

TS
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:

TS
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:

TS
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):

TS
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):

TS
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

Esercizio#ts.m3.l2.e1
Tentativi: 0Caricamento…

Completa la funzione generica identity in modo che accetti un parametro value di tipo generico T e lo restituisca senza modifiche.

Caricamento editor…
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

Esercizio#ts.m3.l2.e2
Tentativi: 0Caricamento…

Definisci un'interfaccia generica chiamata Box che accetta un parametro di tipo T e ha una singola proprietà chiamata content di tipo T.

Caricamento editor…
Mostra suggerimento

Usa la sintassi interface Box<T> { content: T; }.

Soluzione disponibile dopo 3 tentativi

Esercizio 3: Constraint Generico

Esercizio#ts.m3.l2.e3
Tentativi: 0Caricamento…

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.

Caricamento editor…
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

Esercizio#ts.m3.l2.e4
Tentativi: 0Caricamento…

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>.

Caricamento editor…
Mostra suggerimento

Usa la sintassi per due parametri generici Pair<T, U> e definisci makePair di conseguenza.

Soluzione disponibile dopo 3 tentativi