f in x
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Sviluppo di siti web

TypeScript da Zero ad Avanzato — Tipizzazione, Generics e Pattern per Codice che Non Si Rompe

[2026-06-21] Author: Ing. Calogero Bono

Hai un progetto JavaScript che cresce e gli errori 'undefined is not a function' a runtime diventano il tuo incubo quotidiano? Passi più tempo a fare debug che a scrivere feature nuove? Noi di Meteora Web ci siamo passati tante volte. Quando gestiamo piattaforme per i nostri clienti – e-commerce con WooCommerce custom, CRM in Laravel con frontend Vue, app React – sapere che un tipo sbagliato può mandare in crash tutto il sistema non è un'opzione. TypeScript non è una moda: è la risposta concreta a un problema economico. Ogni bug che intercetti a compile time è ora di sviluppo che non paghi in assistenza post-lancio. Ogni funzione tipizzata è documentazione viva che il tuo team futuro ti ringrazierà.

In questa pillar page vediamo TypeScript da zero ad avanzato: dalla configurazione del tsconfig.json ai Generics, dagli Utility Types all'integrazione con React e Node.js. Nessun manuale accademico, ma quello che usiamo ogni giorno in produzione. Pronti?

Perché TypeScript è meglio di JavaScript puro per progetti reali?

JavaScript è un linguaggio fantastico per iniziare, ma quando il codice supera le 10.000 righe – o quando lavori in team – l'assenza di tipi si trasforma in costo. Un parametro passato come stringa invece che numero viene scoperto solo a runtime, magari in produzione. Noi, in passato, abbiamo visto interi carrelli e-commerce bloccarsi per un typeof dimenticato. Con TypeScript il compilatore (o l'IDE) ti avvisa prima di eseguire il codice.

Vantaggi misurabili:

  • Riduzione dei bug del 15-20% secondo studi accademici (vedi Typescript vs JavaScript: A Study on Code Quality).
  • Refactoring sicuro: cambi un tipo e il compilatore segnala tutte le violazioni.
  • Autocompletamento e documentazione inline: il tuo editor diventa un'estensione del cervello.
  • Meno test unitari necessari: il type-checking copre già molti casi limite.

Azione concreta: Se stai iniziando un nuovo progetto, parti direttamente con TypeScript. Se hai un progetto JS esistente, attiva allowJs nel tsconfig e inizia a rinominare file da .js a .ts partendo dai moduli più critici.

Sponsored Protocol

Come configurare TypeScript correttamente con tsconfig.json?

Il file tsconfig.json è il cuore della configurazione. Noi usiamo quasi sempre queste opzioni come base:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Spiegazione:

  • strict: true – abilita tutte le verifiche rigorose (noImplicitAny, strictNullChecks, etc.). È il vero valore aggiunto di TypeScript.
  • target: ES2020 – permette async/await, Promise, Map, Set senza polyfill.
  • module – per Node.js usiamo commonjs; per frontend moderno o con bundler usiamo ES2020 o ESNext.
  • esModuleInterop – evita problemi con import/export e moduli CommonJS.
  • skipLibCheck – velocizza la compilazione saltando i controlli dei file .d.ts esterni.

Azione concreta: Crea un nuovo progetto con npx tsc --init e poi modificalo con le opzioni sopra. Esegui npm install typescript --save-dev e avvia la compilazione con npx tsc.

Quali sono i tipi base di TypeScript e come usarli?

TypeScript estende i tipi di JavaScript con alcuni fondamentali:

  • any – disabilita il type-checking. Da evitare quasi sempre.
  • unknown – come any, ma obbliga a un controllo prima di usare il valore.
  • never – rappresenta un valore che non si verifica mai (es. funzione che lancia sempre eccezione).
  • void – per funzioni che non restituiscono nulla.
  • null e undefined – con strictNullChecks attivo non sono assegnabili automaticamente.
let nome: string = "Mario";
let eta: number = 30;
let isAdmin: boolean = false;

// unknown richiede type guard
let input: unknown = "ciao";
if (typeof input === "string") {
  console.log(input.toUpperCase());
}

// never
function errore(messaggio: string): never {
  throw new Error(messaggio);
}

Azione concreta: Rivedi il tuo codice: trasforma ogni any in unknown e aggiungi type guard dove necessario. Attiva noImplicitAny per catturare variabili non tipizzate.

Sponsored Protocol

Interface vs Type: quando usare quale in TypeScript?

Sia interface che type permettono di definire strutture dati, ma hanno differenze pratiche:

  • Interface – può essere estesa (extends), dichiarata più volte (declaration merging). Ideale per oggetti e classi.
  • Type – può creare union, intersection, mapped types. Più flessibile per composizioni complesse.
interface Utente {
  nome: string;
  eta?: number;
}

interface Admin extends Utente {
  ruolo: "admin";
}

type ID = string | number;
type Ruolo = "user" | "admin";
type UtenteCompleto = Utente & { ruolo: Ruolo };

Regola pratica: Usa interface per oggetti che rappresentano entità (User, Product) e type per alias di tipi primitivi, union o tuple. Noi, nei nostri progetti, preferiamo interface per API e type per utility.

Azione concreta: Scegli una parte del tuo codice e converti le definizioni di oggetto da type a interface, verificando se hai bisogno di declaration merging.

Come funzionano i Generics in TypeScript per codice riutilizzabile?

I Generics permettono di scrivere funzioni, classi e interfacce che lavorano con tipi senza conoscerli a priori. È come avere un placeholder di tipo che viene legato al momento dell'uso.

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

const primoNumero = primoElemento([1, 2, 3]); // number
const primaStringa = primoElemento(["a", "b"]); // string

Vincoli (constraints) con extends per limitare i tipi ammessi:

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

ottieniLunghezza("ciao"); // ok, string ha length
ottieniLunghezza([1,2]); // ok

Applicazione pratica: I Generics sono alla base di librerie come React (type dei props), Express (Request/Response tipizzati) e utility type come Pick, Omit. Noi li usiamo quotidianamente per creare hook generici o middleware tipizzati.

Azione concreta: Scrivi una funzione generica che accetti un array e restituisca un oggetto con il primo e ultimo elemento. Tipizza anche l'oggetto di ritorno.

Sponsored Protocol

Quali Utility Types di TypeScript ti servono davvero?

TypeScript mette a disposizione una serie di utility type che trasformano i tipi esistenti. Ecco i più usati:

  • Partial<T> – rende tutte le proprietà opzionali.
  • Required<T> – rende tutte le proprietà obbligatorie.
  • Readonly<T> – rende le proprietà di sola lettura.
  • Pick<T, K> – estrae un sottoinsieme di proprietà.
  • Omit<T, K> – esclude un insieme di proprietà.
  • Record<K, T> – crea un oggetto con chiavi di tipo K e valori di tipo T.
interface Prodotto {
  id: number;
  nome: string;
  prezzo: number;
}

// Per aggiornamenti parziali
const aggiornamento: Partial<Prodotto> = { prezzo: 29.99 };

// Per un report senza id
const report: Omit<Prodotto, "id"> = { nome: "Scarpe", prezzo: 99 };

// Per mappare utenti per ID
const mappa: Record<number, Utente> = { 1: { nome: "Mario" } };

Azione concreta: Rivedi le tue interfacce e usa Partial per funzioni di update, Pick per viste parziali, Readonly per oggetti che non devono essere modificati.

Come usare TypeScript con React per componenti type-safe?

Con React, TypeScript migliora radicalmente l'esperienza di sviluppo. Ecco gli aspetti essenziali:

Props tipizzate

interface ButtonProps {
  label: string;
  onClick: () => void;
  disabled?: boolean;
  variant?: "primary" | "secondary";
}

const Button: React.FC<ButtonProps> = ({ label, onClick, disabled, variant }) => {
  return <button onClick={onClick} disabled={disabled} className={variant}>{label}</button>;
};

Hook generici

function useForm<T>(initial: T) {
  const [values, setValues] = useState<T>(initial);
  const handleChange = (key: keyof T, value: T[keyof T]) => {
    setValues(prev => ({ ...prev, [key]: value }));
  };
  return { values, handleChange };
}

TypeScript ti permette anche tipizzare eventi e ref in modo preciso:

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setValue(e.target.value);
};

Attenzione: usa React.FC con cautela perché aggiunge automaticamente i figli. Preferisci interfacce esplicite per i children se necessario.

Sponsored Protocol

Azione concreta: Se lavori con React, aggiungi TypeScript al tuo progetto con npm install @types/react @types/react-dom e inizia a tipizzare i componenti uno alla volta.

Come integrare TypeScript con Node.js e Express?

Per backend tipizzato, TypeScript è un alleato potente. Con Express, però, la tipizzazione di request e response non è automatica.

import express, { Request, Response, NextFunction } from 'express';

interface Utente {
  id: number;
  nome: string;
}

const app = express();

app.get('/api/users/:id', (req: Request, res: Response) => {
  const userId = parseInt(req.params.id);
  // ... logica
  const utente: Utente = { id: userId, nome: 'Mario' };
  res.json(utente);
});

// Middleware tipizzato
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  console.error(err.stack);
  res.status(500).send('Errore!');
});

Per gestire meglio le richieste con body, puoi creare interfacce personalizzate e persino estendere l'oggetto Request di Express con moduli augment (declaration merging).

Azione concreta: In un progetto Node.js esistente, installa @types/express e converti il primo endpoint in TypeScript. Aggiungi l'opzione strict per vedere dove mancano tipi.

I Decorators in TypeScript: servono davvero a qualcosa?

I decorators sono una feature sperimentale (attualmente in stage 2) che permette di aggiungere metadati a classi, metodi e proprietà. Framework come NestJS li usano per definire dependency injection, routing, validazione.

function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`Chiamato ${propertyKey} con`, args);
    return original.apply(this, args);
  };
}

class MiaClasse {
  @log
  saluta(nome: string) {
    return `Ciao ${nome}`;
  }
}

Per abilitarli, devi impostare experimentalDecorators: true nel tsconfig.json. Noi li usiamo pochissimo al di fuori di NestJS e librerie di validazione come class-validator. Se non lavori con quei framework, probabilmente non ti servono. Meglio concentrarsi su pattern più moderni come composizione funzionale.

Sponsored Protocol

Azione concreta: Se usi NestJS o TypeORM, studia come i decoratori semplificano la dichiarazione dei modelli. Altrimenti, salta pure questa feature.

Come migrare un progetto da JavaScript a TypeScript senza dolore?

La migrazione può essere graduale. Strategia collaudata:

  1. Installa TypeScript e crea un tsconfig.json con allowJs: true e strict: false inizialmente.
  2. Rinomina i file da .js a .ts partendo da quelli con meno dipendenze.
  3. Attiva strict: true solo dopo aver tipizzato la maggior parte dei moduli.
  4. Usa // @ts-expect-error temporaneamente per bloccare errori noti che risolverai dopo.
  5. Per i file che non vuoi ancora tipizzare, mantieni l'estensione .js e importali normalmente.

Noi abbiamo migrato un progetto Laravel+Vue con 20.000 righe in circa 2 settimane lavorando per moduli, partendo dal backend API.

Azione concreta: Scegli un modulo isolato (es. una utility function) e convertilo in TypeScript con tipi di base. Misura quanti bug emergono grazie al type-checking.

In sintesi: cosa fare adesso

  • Inizia subito: se non usi TypeScript, installalo nel tuo progetto attuale con allowJs e parti da un file.
  • Configura strict: true: è la scelta che dà più valore. Affronta i warning uno a uno.
  • Usa i Generics per funzioni e componenti riutilizzabili – riducono codice duplicato.
  • Utility Types per non reinventare la ruota: Partial, Pick, Omit ti salvano tempo.
  • Non avere paura degli errori: ogni errore di compilazione è un bug che non arriva in produzione.

TypeScript non è un ornamento: è uno strumento che aumenta la qualità del codice e riduce i costi di manutenzione. Noi di Meteora Web lo usiamo ogni giorno – da stack Laravel/Vue a piattaforme React personalizzate – e i risultati parlano chiaro: meno bug, team più produttivi, clienti più soddisfatti. Se vuoi approfondire un aspetto specifico, scrivici o consulta la documentazione ufficiale e le cheatsheet. Buon coding.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ 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()