View on GitHub

TS-Namespaces-ES-Modules

A repository to discuss how to use TypeScript namespaces in harmony with EcmaScript modules

TS-Namespaces and ES-Modules

Jirka Dell'Oro-Friedl, June 2021

Read this page in nice format and view the examples running on Github-Pages


I love TypeScript and I love namespaces in TypeScript!

I can spread my project over several files, for example create a file for each class, and compile it all together in one single Javascript file, without the need of imports and extra code for module handling etc. It’s nice and easy to create a clean and well structured package, easy to load into the browser using the most simple script tag in HTML.

However, there is also the need to load packages and libraries at runtime without preloading via HTML. In the past, various module loaders were created for this, like CommonJS, AMD etc. Fiddling around with the TypeScript-configurations for this drove me nuts. With ES6, a standard loader was introduced and is or will be supported by all browsers natively. So it appears to be recommendable to focus on this.

Unfortunately, ES-Modules appear not to go well together with the beloved namespaces. There are third party tools and bundlers that address this problem to some extend, but I consider the TypeScript-compiler so powerful, that it should not have that problem in the first place. In this little playground, I’ll try to fiddle around to see what can be done.

  1. I’ll create a little library with some code structures to test and a program to consume this library. This will be done on the basis of simple scripts using namespaces. So there is a folder Library containing the code for the library, and a folder Consumer containing the code for the program using the library. The code is spread over multiple files and comprises two corresponding namespaces. Both folders contain the configurations to compile to corresponding Javascript-, map- and declaration files in the folder Build.
  2. From that base, I’ll convert the result to modules to see what is necessary for this and for making it work. Only the js-files are used and altered in order to see what TypeScript would have to do, not what it currently does.
  3. Then I’ll try to mix both approaches having the library still as a module, built with namespaces, but the consuming code as a simple script using namespaces. Again, I’ll work on the Javascript-level.

At this point of time, the changes are minimal to get these tests working. It’s actually almost shocking considering the many people struggling with it and projects merely failing because of it. And it seems as if it should to be possible to have the TypeScript-compiler taking care of this, thus bringing together the best of the module- and the namespace-world directly out of the box. However, this process has not been tested against various use-cases, so comments, ideas, improvements and any help is greatly appreciated. Maybe a proposal to the TypeScript-developers evolves from this…
Please post issues here: https://github.com/JirkaDellOro/TS-Namespaces-ES-Modules/issues

1. Pure namespaces

See example PureNamespace

2. Pure module

See example PureModule
Making the program being based on ES-modules via the TypeScript compiler is a desaster. Compiling into one file is only possible with system or amd, so switching to any other module-directive emits one js-file for each ts-file. It would be necessary to use a bundler to pack them back into one file. Also, using imports in the TypeScript code deters the use of namespaces. TypeScript tells that the namespace is declared but never used and won’t find declarations in other files, though appearently in the same namespace. It’s then necessary in every file to explicitely import everything used in that file. While using modules this way reduces clutter in the global scope at runtime, it appears to me that it adds a lot of clutter, additional workload and a bloated toolchain at design time.


But astonishingly, it seems to be quite easy to convert the compiled code from the PureNamespace-example to modules:


3. Mix module and namespace

See example MixModuleNamespace