ProgrammazioneSviluppatore Frontend

Spiega la meccanica del Narrowing dei tipi (Type Narrowing) in TypeScript. Quali sono i modi per ristrettare i tipi delle variabili e a cosa serve?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Il Narrowing dei tipi (Type Narrowing) in TypeScript è un processo in cui il compilatore "capisce" che in una certa sezione di codice una variabile ha un tipo più specifico, a seconda delle condizioni.

Tecniche comuni di narrowing:

  • Controllo tramite l'operatore typeof:
function example(x: number | string) { if (typeof x === 'string') { // x: string qui return x.toUpperCase(); } else { // x: number qui return x.toFixed(2); } }
  • Controllo tramite instanceof (per classi):
if (dateObj instanceof Date) { // dateObj: Date }
  • Controllo per null e undefined:
function print(value?: string) { if (value != null) { // value: string console.log(value.length); } }
  • Controllo utilizzando "proprietà discriminatorie" (discriminant properties):
type Pet = { kind: 'dog'; woof: () => void } | { kind: 'cat'; meow: () => void }; function sound(pet: Pet) { if (pet.kind === 'dog') { pet.woof(); } else { pet.meow(); } }

TypeScript supporta anche funzioni predicato personalizzate:

function isString(x: unknown): x is string { return typeof x === 'string'; }

Il narrowing rende i controlli dei tipi più sicuri e il codice più affidabile.

Domanda trabocchetto.

È possibile garantire il narrowing del tipo tramite confronti normali (ad esempio, ==/===), e funziona sempre?

Risposta: No. Non in tutti i casi TypeScript comprende il tipo da confronti semplici, specialmente se il confronto è troppo "vago" o avviene tramite variabili/proprietà indirette. Per il narrowing è spesso necessario utilizzare meccaniche esplicite (typeof, instanceof, proprietà discriminatorie e type guard).

Esempio:

function foo(x: number | string | null) { if (x) { // x: string | number, null non è più possibile, ma non ci sarà un narrowing a specifico } }

Storia

In un grande progetto TypeScript, la condizione di tipo user.role == 'admin' non ha ristretto il tipo di dati, e sono state comunque necessarie verifiche per l'esistenza della proprietà. Gli sviluppatori hanno sottovalutato le regole di narrowing, portando a errori "Cannot read property ... of undefined".


Storia

In un'app mobile, una funzione accettava un oggetto o una stringa. Attraverso una chiamata indiretta a una funzione che cambiava tipo, il narrowing non avveniva e su alcuni dispositivi si verificava un crash durante la chiamata a un metodo assente nella stringa. I test sono falliti in casi rari.


Storia

Durante la migrazione di codice da JavaScript a TypeScript, non sono state implementate le proprie funzioni type guard, supponendo che i controlli sulle proprietà avrebbero sempre ristretto il tipo. Di conseguenza, oggetti complessi con campi opzionali si comportarono in modo errato e durante il runtime si verificarono errori di accesso ai dati imprevedibili.