ProgrammazioneSviluppatore Backend

Come funziona il meccanismo di tipizzazione dei simboli (Symbol) in TypeScript? Quali vantaggi e caratteristiche ci sono nell'utilizzare Symbol come chiavi degli oggetti e quali aspetti bisogna considerare nella progettazione di API in TypeScript?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Storia della questione:

Il tipo Symbol è stato aggiunto in JavaScript (ES6) per creare identificatori unici che non si sovrappongano ad altre proprietà dell'oggetto. TypeScript supporta i simboli sin dall'inclusione della compatibilità con ES6.

Problema:

Prima dell'arrivo di Symbol, le stringhe erano spesso utilizzate come chiavi per le proprietà degli oggetti. Ciò portava a errori durante l'estensione o il riutilizzo degli oggetti: collisioni casuali nei nomi e impossibilità di nascondere le proprietà private (anche solo tramite convenzioni). Symbol ha permesso di creare chiavi uniche, invisibili al codice esterno, ma sono sorte domande sulla tipizzazione: come descrivere i tipi con chiavi Symbol e usarli in modo sicuro nelle API?

Soluzione:

TypeScript supporta i simboli come valori e tipi, tuttavia la tipizzazione delle chiavi Symbol ha delle peculiarità. Un simbolo può essere creato usando il costruttore globale o il registro globale dei simboli. Negli interface o nei tipi, le chiavi con simboli devono esplicitamente indicare il tipo come symbol, mentre l'accesso a tali proprietà avviene solo tramite un riferimento salvato al Symbol.

Esempio di codice:

const SECRET = Symbol('secret'); interface SecretObject { [SECRET]: string; visible: string; } const obj: SecretObject = { visible: 'see me', [SECRET]: 'hidden', }; console.log(obj.visible); // 'see me' // console.log(obj["secret"]); // Errore: questa proprietà non esiste! console.log(obj[SECRET]); // 'hidden'

Caratteristiche principali:

  • Symbol garantisce l'unicità della chiave della proprietà, cosa impossibile per qualsiasi chiave stringa.
  • Le proprietà con chiavi Symbol non vengono visualizzate durante la normale iterazione (for...in, Object.keys). Questo è utile per le proprietà nascoste.
  • Non tutte le operazioni standard (ad esempio, JSON.stringify) considerano le chiavi Symbol: questo è importante per la serializzazione e la deserializzazione.

Domande insidiose.

Può Symbol essere convertito automaticamente in una stringa quando utilizzato negli oggetti?

No, Symbol non può essere convertito automaticamente in una stringa; provare a farlo (ad esempio, tramite concatenazione) genererà un errore.

const mySymbol = Symbol('desc'); // alert('prefix_' + mySymbol); // TypeError

Posso elencare le chiavi Symbol tramite Object.keys?

No, Object.keys e for...in ignorano le chiavi Symbol. Per ottenere tali chiavi si utilizza Object.getOwnPropertySymbols.

const sym = Symbol('a'); const obj = { [sym]: 42 }; Object.keys(obj); // [] Object.getOwnPropertySymbols(obj); // [Symbol(a)]

Le proprietà con chiavi Symbol vengono trasferite durante la copia tramite Object.assign?

Sì, Object.assign copia sia le chiavi stringa che quelle simboliche, a differenza di JSON.stringify.

const s = Symbol('s'); const o1 = { [s]: 123, foo: 'bar' }; const o2 = Object.assign({}, o1); o2[s]; // 123

Errori tipici e anti-pattern

  • Creazione di simboli direttamente in più luoghi (Symbol(…) riutilizzati implicitamente). Questo porta a chiavi diverse e non coincidenti.
  • Lavorare con chiavi Symbol come fossero stringhe ordinarie: questo causa errori di accesso e perdita di proprietà.
  • Aspettativa di serializzazione delle chiavi Symbol tramite JSON.stringify: tali proprietà si perdono.

Esempio dalla vita reale

Caso negativo

Un sviluppatore ha utilizzato chiavi stringa per proprietà private ('_private'), basandosi su convenzioni. Nel Team B è stata accidentalmente aggiunta la stessa stringa: le proprietà si sono sovrapposte, causando un errore imprevedibile.

Pro:

  • Rapido prototipaggio.

Contro:

  • Nessuna vera privacy.
  • Possibilità di collisione nei nomi.
  • Perdita di dati tra le parti del sistema.

Caso positivo

Un secondo sviluppatore ha utilizzato Symbol per proprietà nascoste (ad esempio, Symbol('internal')). Ora, anche all'interno del team, non è possibile sovrascrivere accidentalmente i dati interni: l'accesso è possibile solo se si ha un riferimento al Symbol specifico.

Pro:

  • Privacy affidabile.
  • Rischio minimo di collisioni.

Contro:

  • Interfaccia non ovvia per i nuovi dipendenti.
  • Più difficile fare debug dei campi nascosti.