11

I am a little confused about the difference between declare module and declare namespace in typescript internal modules.

Another point which I am not clear: is it a good idea to have complex namespaces to typescript internal modules.

e.g.

declare module com.xyz.company.test.mynamespace {
    interface Iabc {
        // stuff  
    }

    interface Ixys{ 
       //stuff 
    }

    // or

    export interface Ipqr { 
        // stuff 
    }
}
terahertz
  • 2,915
  • 1
  • 21
  • 33
Ankur Soni
  • 746
  • 6
  • 17

2 Answers2

9

I found this [1] handbook on namespaces and modules. First of all this clarification about terms:

A note about terminology: It’s important to note that in TypeScript 1.5, the nomenclature has changed. “Internal modules” are now “namespaces”. “External modules” are now simply “modules”, -

So, from the same book, different chapter [2] example of both:

Module

  interface StringValidator {
      isAcceptable(s: string): boolean;
  }
  ..
   // Validators to use
  let validators: { [s: string]: StringValidator; } = {};

Namespace

  namespace Validation {
      export interface StringValidator {
          isAcceptable(s: string): boolean;
      }
   ...
    // Validators to use
    let validators: { [s: string]: Validation.StringValidator; } = {};

Source [3] tells about their usage:

Namespaces that aren't in an external module can span files, so if you're in the same namespace you can refer to anything exported by the namespace without needing any sort of import.

This is case, where you maybe could use namespace but there are mentions in [4] this comparison:

Module:

   //typescript
   export class Validaton { 
       ... 
   }

   //becomes, in javascript:
   export class Validation {
       ... 
   }

Namespace:

   // typescript:
   namespace Validation {
       const foo = 123;
   }

  //This becomes, in es6:
  (function(Validation) {
         Validation.foo = 123;
   })(Validation || (Validation = {}))

and as you see, the second one becomes in JavaScript ES6 quite unnatural and thus another answer on [3] even states namespaces obsolete.


About second question:

Source [1] tells about a case, where overly using namespaces makes code look little bit uselessly complicated:

   import * as shapes from "./shapes";
   let t = new shapes.Shapes.Triangle(); // shapes.Shapes?

So, this makes me think: all useless or less meaningful for the code namespace levels should be avoided. The writer even says:

A key feature of modules in TypeScript is that two different modules will never contribute names to the same scope. Because the consumer of a module decides what name to assign it, there’s no need to proactively wrap up the exported symbols in a namespace.


Source:

[1] https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html

[2] https://www.typescriptlang.org/docs/handbook/namespaces.html#validators-in-a-single-file

[3] Module vs Namespace - Import vs Require Typescript

[4] https://michelenasti.com/2019/01/23/is-typescript-namespace-feature-deprecated.html

mico
  • 12,730
  • 12
  • 59
  • 99
8

The declare keyword is used to create ambient declarations in typescript, providing the compiler with type informations about each module.

Before ES6, JavaScript has no concept of module. Every variable you create will end up on the global scope. eg. If you have the following 2 files:

// a.js
var name = 'a';
// b.js
var name = 'b';

name will be a global variable, so if b.js is loaded after a.js, name will have the value of 'b';

The module pattern was introduced to prevent these variable clashes:

// a.js
(function() {
    var name = 'a';
})();
// b.js
(function() {
    var name = 'b';
})();

Now each file will have its own name variable within the function scope. They cannot be accessed outside the function.

When you want to export the variables, you can do so by passing in a global variable:

var module = {}; // this is global

// a.js
(function(mod) {
    var name = 'a';
    mod.a = name;
})(module); // <-- passing the module variable into the function scope of a.js

// b.js
(function(mod) {
    var name = 'b';
    mod.b = name;
})(module);

Now the values have been exported to module.a and module.b. Before ES6 this is the mechanism used by many JS libraries to create modules. Typescript called this mechanism internal modules which has subsequently been renamed to namespaces.

Namespaces are simply named JavaScript objects in the global namespace

The ambient type declaration of these global module variables can be defined using the declare namespace syntax.



Since the introduction of ES6, module has become a feature of the language itself, and can be created using the import & export syntax. The type declarations of these modules will therefore use the declare module syntax.

Starting with ECMAScript 2015, modules are native part of the language, and should be supported by all compliant engine implementations. Thus, for new projects modules would be the recommended code organization mechanism

https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html


As for your second question, it is generally a better design to reduce the level of nesting for your module objects when possible.

Edwin
  • 1,184
  • 9
  • 9