TypeScript 5.7: Novità e Miglioramenti per Sviluppatori

La nuova versione TypeScript 5.7 introduce miglioramenti significativi, pensati per aumentare la flessibilità e ridurre il lavoro ripetitivo durante lo sviluppo. In questo articolo, vedremo le novità di TypeScript e capiremo come possono migliorare il nostro codice con esempi pratici.


1. Miglioramenti ai Tipi Condizionali: Scrivere Codice più Flessibile

I tipi condizionali in TypeScript permettono di definire tipi dinamici, cioè tipi che cambiano in base alle condizioni che stabiliamo. In TypeScript 5.7 questa funzionalità è stata migliorata, rendendo la scrittura del codice più semplice e precisa.

Esempio pratico:

type IsString<T> = T extends string ? "È una stringa" : "Non è una stringa";

type Test1 = IsString<string>;  // "È una stringa"
type Test2 = IsString<number>;  // "Non è una stringa"

Valore aggiunto

  • Riduce gli errori legati alla gestione dei tipi.
  • Aumenta la leggibilità del codice, soprattutto nei progetti complessi.
  • Ti permette di creare logiche più robuste direttamente nei tipi, senza bisogno di codice extra.

2. Supporto per i Decorator: Aggiungi Funzionalità Senza Modificare il Codice Esistente

Per utilizzare i decorator, è necessario abilitare l’opzione experimentalDecorators nel file tsconfig.json.

Configurazione minima per tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

I decorator sono una funzionalità sperimentale che consente di aggiungere funzionalità ai metodi e alle classi senza doverli riscrivere. Questo è particolarmente utile per operazioni come logging, validazione dei dati o gestione delle autorizzazioni.

Esempio pratico:

function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`Metodo ${propertyKey} chiamato con argomenti: ${JSON.stringify(args)}`);
    return originalMethod.apply(this, args);
  };
}

class Calculator {
  @Log
  add(a: number, b: number) {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3); // Console: "Metodo add chiamato con argomenti: [2, 3]"

Valore aggiunto

  • Elimina codice ripetitivo, mantenendo il progetto più pulito.
  • Perfetto per applicare comportamenti comuni (come log o gestione degli errori) in modo modulare.
  • Facilita la creazione di architetture scalabili e più facili da mantenere.

3. Nuova Opzione rewriteRelativeImportExtensions: Gestione Automatica delle Estensioni dei File

Il problema: Gestione manuale delle estensioni dei file

Quando scrivi codice TypeScript, i file .ts o .tsx vengono compilati in file .js. Tuttavia, nelle importazioni relative (import da file locali), TypeScript non riscrive automaticamente le estensioni dei file, lasciando le importazioni come .ts. Questo può creare problemi nel codice JavaScript compilato.
In pratica, se lasci un’importazione così:

// myModule.ts
import { myFunction } from './utils/helper.ts';  // .ts non valido nel codice JavaScript

Una volta compilato, il file JavaScript mantiene l’estensione .ts, generando un errore di runtime, perché Node.js o il browser non riconoscono i file con l’estensione .ts.


La soluzione: rewriteRelativeImportExtensions

Con TypeScript 5.7, puoi configurare il compilatore per riscrivere automaticamente le estensioni dei file .ts, .tsx, .mts, e .cts come .js, .mjs o .cjs nei file di output JavaScript. Questo garantisce che le importazioni siano sempre valide nel codice finale.

Configurazione in tsconfig.json:

{
  "compilerOptions": {
    "module": "ESNext",
    "rewriteRelativeImportExtensions": true
  }
}

Esempio pratico completo

Prima di TypeScript 5.7 (Problema)

// utils/helper.ts
export function greet(name: string) {
  return `Ciao, ${name}!`;
}

// main.ts
import { greet } from './utils/helper.ts';  // Questa importazione NON funzionerà in JavaScript
console.log(greet('TypeScript'));

Codice compilato (JavaScript):

// main.js
import { greet } from './utils/helper.ts';  // Errore! Node.js non riconosce l'estensione .ts
console.log(greet('TypeScript'));

Errore di runtime: Cannot find module './utils/helper.ts'

Dopo TypeScript 5.7 (Soluzione)

Con la nuova opzione rewriteRelativeImportExtensions, TypeScript cambia automaticamente .ts in .js nel codice compilato.

Codice TypeScript invariato:

// main.ts
import { greet } from './utils/helper.ts';
console.log(greet('TypeScript'));

Codice compilato (JavaScript) con rewriteRelativeImportExtensions:

// main.js
import { greet } from './utils/helper.js';  // Corretto! L'estensione è ora .js
console.log(greet('TypeScript'));

Risultato: Nessun errore, il codice funziona correttamente nel runtime JavaScript.


Valore aggiunto

  • Evita errori di runtime dovuti a importazioni non valide.
  • Riduce il lavoro manuale, specialmente nei progetti con molte importazioni relative.
  • Migliora la compatibilità con Node.js, Deno e ambienti basati su ES Modules.

4. Controllo delle Variabili Mai Inizializzate

Il problema: Variabili di classe non inizializzate

Prima di TypeScript 5.7, TypeScript non segnalava errori se una variabile dichiarata in una classe non veniva inizializzata né direttamente né nel costruttore. Questo poteva portare a errori di runtime quando si tentava di accedere a variabili undefined.

La soluzione in TypeScript 5.7

Ora, TypeScript verifica automaticamente se una variabile membro di una classe non è mai stata inizializzata e segnala un errore.

Esempio prima di TypeScript 5.7 (Nessun errore, ma possibile bug)

class User {
  name: string;  // ❌ Questo non generava errori, ma poteva causare problemi a runtime
}

const u = new User();
console.log(u.name.length);  // ⚠️ Errore a runtime: Cannot read properties of undefined

Esempio con TypeScript 5.7 (Errore segnalato)

class User {
  name: string;  // ❌ Errore: La proprietà 'name' non ha un valore iniziale e non è assegnata nel costruttore.
}

Il compilatore TypeScript ora avvisa che name non è inizializzata e potrebbe portare a problemi.

Come risolvere il problema

1️⃣ Inizializzare la variabile direttamente

class User {
  name: string = "Nome predefinito";  // ✅ Nessun errore
}

2️⃣ Inizializzare la variabile nel costruttore

class User {
  name: string;
  
  constructor(name: string) {
    this.name = name;  // ✅ Nessun errore
  }
}

3️⃣ Usare l’operatore ! (Non consigliato a meno che non si sia certi)

class User {
  name!: string;  // ⚠️ Disabilita il controllo, ma usare con attenzione
}

Questa opzione disattiva il controllo, quindi usala solo se sei sicuro che la variabile verrà inizializzata prima di essere usata.

Benefici di questa novità

✅ Previene errori di runtime dovuti a variabili non inizializzate.
✅ Rende il codice più sicuro e affidabile.
✅ Aiuta a identificare potenziali bug prima dell’esecuzione.


5. Miglioramenti alle Prestazioni: Compilazione più Veloce

Oltre alle nuove funzionalità, TypeScript 5.7 include ottimizzazioni che riduccono i tempi di compilazione e migliorano l’esperienza dello sviluppatore. Meno attesa significa più tempo per concentrarsi sul codice.


Conclusione

TypeScript 5.7 offre nuove funzionalità utili per rendere il codice più flessibile, sicuro e facile da mantenere. I miglioramenti ai tipi condizionali e il supporto per i decorator sono strumenti preziosi che possono semplificare il lavoro quotidiano degli sviluppatori.

Aggiorna alla versione 5.7 per sfruttare al massimo queste novità e consulta la documentazione ufficiale per ulteriori dettagli.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Torna in alto