Passer au contenu principal
eLearner.app
Module 3 · Leçon 2 sur 26/14 dans le cours~15 min
Leçons du module (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

Exercice#ts.m3.l2.e1
Tentatives : 0Chargement…

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

Chargement de l'éditeur…
Afficher l'indice

Il tipo di ritorno deve essere lo stesso tipo generico T del parametro.

Solution disponible après 3 tentatives

Esercizio 2: Wrapper Generico Box

Exercice#ts.m3.l2.e2
Tentatives : 0Chargement…

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

Chargement de l'éditeur…
Afficher l'indice

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

Solution disponible après 3 tentatives

Esercizio 3: Constraint Generico

Exercice#ts.m3.l2.e3
Tentatives : 0Chargement…

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.

Chargement de l'éditeur…
Afficher l'indice

Dichiara la funzione come getLength<T extends HasLength>(arg: T): number e ritorna arg.length.

Solution disponible après 3 tentatives

Esercizio 4: Coppia Generica Pair

Exercice#ts.m3.l2.e4
Tentatives : 0Chargement…

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

Chargement de l'éditeur…
Afficher l'indice

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

Solution disponible après 3 tentatives