Search code examples
typescriptmodulenamespacesclass-design

TypeScript: Namespace vs Class


Well it was harder then I thought but I figured out how to encapsulate my code using a namespace

I already know how to do it with a class (I’m coming from C# world)

And for the question, I had a small class that just needed an initiation and then it start working (without exporting any function or property) to do its infinite internal job.

I was told that in my case it’s not a good practice to use a class, because I’ll always have only one instance that not exporting anything so I need to use internal module instead...

Now all my code is working great inside of a namespace, is it a good practice to encapsulate it in a class too?

namespace X { class Y { } }

Or should I leave it without a class?

My module code is bunch of functions that works together using a shared internal state.

A great answer will explain with details the reasons when to use a namespace, when to use a class, when to use both, and when to use nothing.

Until now I didn’t find a page that explain the best practice for each, and I believe that a great answer to my question will receive a lot of great feedback (or upvotes ;) ) from confused new comers like me.


Solution

  • Hi and welcome to Typescript.

    First. Since we in javascript land import code using

    import { some_exported_thing } from "./path/to/file_without_ending";
    

    every file is a module, meaning you should avoid namespacing the living daylight out of your classes. The import handles that first namespace layer for you:

    import { Y as less_general_name } from "my_module";
    

    otherwise you will quickly end up with things like:

    import * as X from "my_module";
    console.log(X.X.Y);
    

    Also it makes it difficult for bundlers such as webpack or rollup to analyze your compiled typescript and treeshake (remove unused code through static analyis of dependencies).

    Otherwise a namespace with exported members and a class with static members are very similar and will compile to pretty much the same.

    Just avoid the depricated module statement, since it conflicts with the meaning of a module as a file that you import.

    Here is a link to an example in the TS playground

    EDIT: Adding explaination from comments on request:

    Use namespaces when within a large module you would like to separate blocks of functionality and class when the blocks describe an object or when you jusr want your code more optimizable EDIT ( enter too fast). Generally though namespaces it more often not needed and something we take with us from languages such as c# or java. In your ex i would (if i understand it correctly) make a singleton class in a module (a class with a static get instance function and private constructor or if it is only 1 function, just export it in a module, no objectifiation or namespacing. If you want "namespace" around that function for clairty import like so:

    import * as MyModule from "somewhere";
    MyModule.myexportedFn();