f in x
Generics in TypeScript — Scrivere Codice Riutilizzabile e Type-Safe che Non Si Rompe
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Sviluppo di siti web

Generics in TypeScript — Scrivere Codice Riutilizzabile e Type-Safe che Non Si Rompe

[2026-06-28] Author: Ing. Calogero Bono
Zenithby Meteora Web Il sistema operativo della tua attività. Social, clienti, prenotazioni e fatture in un'unica piattaforma. Palestre, barber, professionisti. Scopri Zenith Demo gratis · senza carta

Hai una funzione che funziona con array di numeri, poi ne serve una identica per stringhe, poi per oggetti. Scrivi tre versioni quasi uguali. Il codice si gonfia, si duplica, e quando devi modificare la logica devi ricordarti di aggiornarle tutte. È un problema concreto che incontriamo spesso nei progetti Laravel e Vue che seguiamo.

Noi, di Meteora Web, lo vediamo nei refactoring: funzioni che prendono any e perdono tutta la sicurezza del tipo, oppure overload manuali che diventano un incubo da mantenere. I Generics risolvono esattamente questo: scrivi la logica una volta sola, lasciando al chiamante la libertà di decidere il tipo, ma con la garanzia che TypeScript controllerà tutto.

In questa guida vediamo cosa sono, come usarli, e come evitare gli errori più comuni. Partiamo dal problema, non dalla teoria.

Cosa sono i Generics in TypeScript e perché servono per codice riutilizzabile?

Un generic è un parametro di tipo. Invece di fissare un tipo (es. number), scrivi <T> e usi T come segnaposto. Quando chiami la funzione, TypeScript deduce il tipo reale da ciò che passi.

Esempio base senza generics:

function firstElement(arr: number[]): number | undefined {
  return arr[0];
}
// Se vuoi per stringhe, la riscrivi:
function firstElementStr(arr: string[]): string | undefined { ... }

Con generics:

Sponsored Protocol

function firstElement<T>(arr: T[]): T | undefined {
  return arr[0];
}

const num = firstElement([1,2,3]);      // type number | undefined
const str = firstElement(['a','b']);     // type string | undefined

Il tipo viene inferito automaticamente. Scriviamo una funzione, non tre. Questo è il cuore della riutilizzabilità senza sacrificare la type safety.

Errori comuni da evitare

Il più frequente? Usare any al posto di un generic. any disabilita i controlli; un generic li mantiene. Un altro errore è dimenticare il tipo restituito: se la funzione restituisce qualcosa di diverso da T, TypeScript te lo segnala.

Come si scrive e utilizza una funzione generica in TypeScript?

La sintassi è semplice: dopo il nome della funzione, tra <>, dichiari uno o più parametri di tipo. Puoi usarli nei parametri, nel tipo di ritorno e nel corpo.

function identity<T>(arg: T): T {
  return arg;
}

// Chiamata esplicita
const result = identity<number>(42);
// Oppure inferita (più comune)
const result2 = identity('ciao');

Puoi avere più generics:

Sponsored Protocol

function merge<A, B>(obj1: A, obj2: B): A & B {
  return { ...obj1, ...obj2 };
}

const merged = merge({ name: 'Alice' }, { age: 30 });
// type: { name: string; } & { age: number; }

Operatività immediata: Apri il tuo progetto TypeScript, trova una funzione che usa any e sostituiscila con un generic. Prova a passare tipi diversi e vedi se TypeScript ti dà errori incoerenti.

Come vincolare i Generics con constraint per maggiore sicurezza?

A volte non vuoi accettare qualsiasi tipo, ma solo quelli che hanno certe proprietà. Usi extends per vincolare il generic.

function getLength<T extends { length: number }>(item: T): number {
  return item.length;
}

getLength('hello');      // ok, string ha length
getLength([1,2,3]);      // ok
getLength(42);           // errore: number non ha length

Un caso più utile: estrarre una proprietà da un oggetto in modo type-safe.

function getProperty<Obj, Key extends keyof Obj>(obj: Obj, key: Key): Obj[Key] {
  return obj[key];
}

const person = { name: 'Mario', age: 35 };
const name = getProperty(person, 'name'); // type string
const age = getProperty(person, 'age');   // type number
// getProperty(person, 'surname'); // errore: 'surname' non in keyof

Questo è un pattern che usiamo quotidianamente nei gestori di stato e nelle API di validazione.

Sponsored Protocol

Condivisione di vincoli tra più generics

function copyFields<T, U extends T>(source: T, target: U): U {
  Object.assign(target, source);
  return target;
}

Garantisce che U abbia almeno le stesse proprietà di T, senza perderne di aggiuntive.

Quando usare tipi generici avanzati: infer, conditional types, mapped types?

I generics non si limitano alle funzioni. Puoi usarli per creare tipi condizionali che cambiano in base al tipo passato.

type IsString<T> = T extends string ? 'yes' : 'no';
type A = IsString<'hello'>; // 'yes'
type B = IsString<42>;       // 'no'

Il costrutto infer permette di estrarre il tipo da un altro tipo complesso:

type ArrayItem<T> = T extends (infer U)[] ? U : never;
type Item = ArrayItem<number[]>; // number

I mapped types usano generics per trasformare le proprietà di un oggetto:

type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

type Point = { x: number; y: number };
type ReadonlyPoint = Readonly<Point>; // { readonly x: number; readonly y: number }

In pratica, li usi quando devi creare utility type su misura. Per esempio, per rendere tutte le proprietà opzionali o obbligatorie in una DTO.

Sponsored Protocol

Operatività: Nel tuo editor, prova a definire un mapped type che aggiunga un prefisso a tutte le chiavi di un oggetto. Usa keyof e template literal types.

Quale errore comune si fa con i Generics e come evitarlo?

L'errore più subdolo: pensare che il generic sia valutato a runtime. Non lo è. I generics sono solo un costrutto a tempo di compilazione. Non puoi fare typeof T o instanceof T nel codice runtime. TypeScript li cancella dopo la compilazione.

function createInstance<T>(ctor: new () => T): T {
  return new ctor();
}
// Questo funziona perché passi il costruttore a runtime, non T.

// Sbagliato:
function logType<T>() {
  console.log(typeof T); // errore: T è solo un tipo
}

Un altro errore è non specificare il generic quando TypeScript non riesce a inferirlo automaticamente. In quei casi, fornisci il tipo esplicitamente.

function wrapInArray<T>(item: T): T[] {
  return [item];
}

const arr = wrapInArray(5); // ok
const arr2 = wrapInArray<string>(5); // errore: 5 non è stringa

Ricorda: il generic non è un any con un altro nome. Se il tuo codice usa il generic solo per passarlo senza controlli, stai annullando il vantaggio.

Sponsored Protocol

Cosa fare adesso

Ecco tre azioni immediate per applicare quello che hai imparato:

  1. Trova nel tuo progetto una funzione che ha overload per due o tre tipi diversi (es. fetchData(url: string): Promise<User> | Promise<Product>). Convertila in un unica funzione generica.
  2. Aggiungi un vincolo extends a una funzione che accetta oggetti con id: number, in modo che il chiamante non possa passare un oggetto senza quella proprietà.
  3. Leggi la sezione ufficiale sui Generics nella TypeScript Handbook per approfondire gli use case avanzati.

I generics sono uno strumento potente: ti permettono di scrivere codice flessibile senza rinunciare alla rigidità del tipo. Noi li usiamo in ogni progetto, dal backend Laravel con TypeScript fino ai componenti Vue. Se vuoi vedere come li applichiamo in contesti reali, dai un'occhiata alla nostra guida completa su TypeScript.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere informatico, fondatore di Meteora Web e Zenith OS. System administrator e progettista di piattaforme, app e CMS proprietari, con esperienza in sviluppo full-stack, marketing digitale ed ecosistema Google.
[ Read Full Dossier ]

> METEORA_WEB // WEB AGENCY

Costruiamo la presenza digitale che la tua azienda merita.

Siti web, social, pubblicità online, e-commerce e hosting performante: ingegnerizzati con metodo da ingegneri informatici a Sciacca, per tutta Italia.

> MW_JOURNAL

> READ_ALL()