Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Namespace and module confusion in typescript?

The official site of Typescript get me ask a question, "Do we need to use namespace or not?".

The following quote explains the 2 things well:

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”, as to align with ECMAScript 2015’s terminology, (namely that module X { is equivalent to the now-preferred namespace X {).

So, they suggest that TS team prefer namespace. Further, it says we should use "namespace" to struct the internal module:

This post outlines the various ways to organize your code using namespaces (previously “internal modules”) in TypeScript. As we alluded in our note about terminology, “internal modules” are now referred to as “namespaces”. Additionally, anywhere the module keyword was used when declaring an internal module, the namespace keyword can and should be used instead. This avoids confusing new users by overloading them with similarly named terms.

The above quote is all from the Namespace section, and yes, it says again, but in a internal secnario.
but in the module section, one paragraph, says that:

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.

Does it mean that I don't need to bother with namespace, use module all along is the suggested way to develop?

like image 540
Albert Gao Avatar asked Oct 31 '22 03:10

Albert Gao


1 Answers

Does it mean that I don't need to bother with namespace, use module all along is the suggested way to develop?

I wouldn't put it exactly that way... here's another paraphrase of what has happened. One upon a time, there were two terms used in Typescript

  1. "external modules" - this was the TS analog to what the JS community called AMD (e.g. RequireJS) or CommonJS (e.g. NodeJS) modules. This was optional, for some people who write browser-based code only, they don't always bother with this, especially if they use globals to communicate across files.
  2. "internal modules" - this is a hierarchical way of organising your variables/functions so that not everything is global. The same pattern exists in JS, it's when people organise their variables into objects/nested objects rather than having them all global.

Along came Ecmascript 2015 (a.k.a. ES6), which added a new formal, standard format that belonged in the "external modules" category. Because of this change, Typescript wanted to change the terminology to match the new Javascript standard (being that it likes to be a superset of Javascript, and tries its best to avoid confusion for users coming from Javascript). Thus, the switch of "external modules" being simplified to just "modules", and "internal modules" being renamed to "namespaces".

The quote you found here:

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.

Is likely alluding to guidance for users who were not yet using (external) modules. To at least consider using it now. However, support for ES6 modules is still incomplete in that browsers as of May 2016 don't have built-in module loaders. So, you either have to add a polyfill (which handles it at runtime) like RequireJS or SystemJS, or a bundler (like browserify or webpack) that handles it at build time (before you deploy to your website).

So, would you ever use both modules (formerly "external modules") and namespaces? Absolutely - I use them both frequently in my codebases. I use (external) modules to organise my code files.

Namespaces in Typescript are extremely useful. Specifically, I use namespace declaration merging as a typesafe way to add extra properties to function objects themselves (a pattern often used in JS). In addition, while namespaces are a lot like regular object variables, you can hang subtypes (nested interfaces, classes, enums, etc.) off of their names.

Here is an example of a function with a property (very common in NodeJS libs):

function someUsefulFunction() {
  // asynchronous version
  return ...; // some promise
}

namespace someUsefulFunction {
  export function sync() {
    // synchronous version
  }
}

This allows for consumers to do this common NodeJS pattern:

// asynchronous consumer
someUsefulFunction()
  .then(() => {
    // ... 
  });

// synchronous consumer
someUsefulFunction.sync();

Similarly, say you have an API that takes in an options object. If that options type is specific to that API,

function myFunc(options?: myFunc.Options) {
    // ...
}

namespace myFunc {
    export interface Options {
        opt1?: number;
        opt2?: boolean;
        opt3?: string;
    }
}

In that case, you don't have to pollute a larger namespace (say whole module scope) with the type declaration for the options.

Hope this helps!

like image 87
Theo Yaung Avatar answered Nov 11 '22 07:11

Theo Yaung