8

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.

Yitzchak
  • 3,303
  • 3
  • 30
  • 50
  • 1
    Are you not already using ES6 modules? That would be the ideal IMO. – Aaron Beall Jan 17 '18 at 20:29
  • @Aaron I guess I do, can you explain with a small piece of code? – Yitzchak Jan 17 '18 at 20:45
  • 1
    Well its just using `export` and `import` syntax in a file. This makes the file an isolated module. At that point using a namespace or class for isolation is not needed, although using a class to create instances and store state is obviously still useful. – Aaron Beall Jan 17 '18 at 20:56

1 Answers1

10

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();
JGoodgive
  • 1,068
  • 10
  • 20
  • Nice answer, I’m just wondering: there is a reason for namespaces, and there is a reason for classes. All of us wants a modular readable and maintainable code, that’s why we have so much definitions (module, class...). what is the purpose of classes vs namespaces?When is the best practice to use each? I’m sure there is a meaning for each. Also, please reference my real life example: my main.ts manages the application, part of his job is to initiate a single instance of a self contained code that’s doing endless job without exporting an API for main.ts to use. What’s the best practice for that? – Yitzchak Jan 18 '18 at 04:03
  • Well. Classes and namespaces are more of a semantical difference since in JS there are only objects and function scopes really.to group code. I would say, use namesoaces when within a 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 – JGoodgive Jan 18 '18 at 08:06
  • Edit failed: 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. – JGoodgive Jan 18 '18 at 08:29
  • 1
    Thanks a lot for the details, I agree that the best fit is to just export the single function I need. But I ended up using a namespace so the call to the function will be more readable: instead of doMyWork() I use MyModule.doMyWork(). Please add the important explanations from your comments to your answer so others will find it easily – Yitzchak Jan 18 '18 at 09:56
  • I guess "using a namespace" mean you do an import * as MyModule from "somewhere"; – JGoodgive Jan 18 '18 at 10:12
  • No my module is like this export namespace MyModule { export function doWork() {} }. and I use it like this: import { MyModule } from ‘filename’. And then: MyModule.doWork() – Yitzchak Jan 18 '18 at 10:14
  • 1
    I would avoid that if it does not bring any value inside 'filename'. Instead use the import * as MyModule to get a namespace. That way your 'filename' module stays clean. – JGoodgive Jan 18 '18 at 11:08
  • what if I want to import and use only some of the functions from another file? Is there a way to add namespacing to those functions? – Jonas Eicher Oct 11 '22 at 14:55