Il Namespace (spazio dei nomi) è un meccanismo di organizzazione del codice, apparso nei tempi del codice pre-ES6, per unire entità logicamente correlate. Aiuta a strutturare grandi progetti, raggruppando classi, funzioni, interfacce e tipi all'interno di un unico spazio dei nomi, per evitare conflitti di nomi e rendere il codice più leggibile.
Storia della questione: prima dell'arrivo degli standard JavaScript ES6, gli sviluppatori utilizzavano IIFE, oggetti e spazi dei nomi per simulare la modularità. TypeScript ha introdotto la parola chiave namespace (precedentemente internal module) per raggruppare il codice.
Problema: i moduli moderni (ES6 Module) sono diventati lo standard, e entrambi gli approcci (namespace e modulo) esistono parallelamente, il che crea confusione nella progettazione dell'architettura: quando è meglio utilizzare un namespace e quando un modulo?
Soluzione: I Namespace sono ancora utili per raggruppare funzioni e tipi ausiliari in progetti puramente TypeScript (ad esempio, durante la generazione di singoli file JS utilizzando outFile). Per separare il codice tra file, specialmente quando si lavora con npm e moderni strumenti di build, è più corretto utilizzare moduli. I Namespaces sono spesso usati in librerie interne, dichiarazioni di tipi e situazioni in cui è necessaria una strutturazione all'interno di un singolo file o nel codice legacy.
Esempio di codice:
namespace MyMath { export function add(a: number, b: number) { return a + b; } } console.log(MyMath.add(2, 3)); // 5
Caratteristiche chiave:
Se si uniscono i namespace da file diversi, ci sarà un unico namespace o più?
TypeScript esegue fusione della dichiarazione (declaration merging) — se i nomi coincidono, diverse parti dello spazio dei nomi vengono unite in uno, se correttamente collegate e si trovano nello stesso ambito.
// mathA.ts namespace MathUtil { export function sum(a: number, b: number) { return a + b; } } // mathB.ts namespace MathUtil { export function mul(a: number, b: number) { return a * b; } } // Dopo la compilazione MathUtil contiene entrambi i metodi
Si possono usare import/require per namespace come per moduli?
No, i namespace non hanno un'esportazione predefinita/nominale, non possono essere importati con la sintassi standard ES6. Il Namespace è un concetto puramente TypeScript che non si traduce in moduli JavaScript.
È possibile importare valori da un namespace in un altro file tramite import?
No, per accedere a un namespace da altri file è necessario utilizzare un riferimento (/// <reference path="..." />) o compilare con outFile, l'importazione tramite import è impossibile.
In un vecchio progetto, la logica era divisa in decine di namespace, nomi identici apparivano in più file, causando a volte unione inaspettata o conflitti. Durante la transizione a un'architettura modulare, il trasferimento del codice è diventato molto laborioso.
Vantaggi:
Svantaggi:
In una grande libreria, sono stati dichiarati API tramite dichiarazioni namespace in un file index.d.ts, unificando tutti i tipi e le interfacce senza codice di implementazione. Questo ha permesso di tipizzare velocemente i consumatori della libreria e di aggiornare facilmente il contratto tra i team.
Vantaggi:
Svantaggi: