Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you put multiple external modules into the same namespace in TypeScript?

Tags:

Say I want to have one class per .ts file. I have two .ts files, that look like so:

export module MyClasses { export class A {} } 

and

export module MyClasses { export class B {} } 

I can't do this:

import MyClasses = module('A'); import MyClasses = module('B'); 

How do I define classes in separate files and put them into the same "namespace"? Furthermore, we end up having to do something like:

MyClasses.MyClasses.A 

instead of

MyClasses.A 

What's the point of this additional level of hierarchy? So that you can have more than one exported module in a module file? The best solution I've figure out so far is to remove "export module" (since "export class" seems to be sufficient when compiling AMD), which moves the class up one hierarchical level. Then:

import AModule = module('A'); module MyClasses{ var A = AModule.A; } import BModule = module('B'); module MyClasses { var B = BModule.B; } 

Though it works perfectly, it's not exactly succinct. Is there not a better way to do this?

like image 692
Brent Avatar asked Oct 14 '12 13:10

Brent


People also ask

How do you define a namespace in TypeScript?

The namespace is used for logical grouping of functionalities. A namespace can include interfaces, classes, functions and variables to support a single or a group of related functionalities. A namespace can be created using the namespace keyword followed by the namespace name.

What is the difference between namespace and module in TypeScript?

A module is a way which is used to organize the code in separate files and can execute in their local scope, not in the global scope. A namespace is a way which is used for logical grouping of functionalities with local scoping.

How do I import a namespace in TypeScript?

Use a file tsconfig. @Pavel_K In the TypeScript handbook: "To reiterate why you shouldn't try to namespace your module contents, the general idea of namespacing is to provide logical grouping of constructs and to prevent name collisions.


2 Answers

Unfortunately there does not seem to be a perfect solution but this is how I solved it for now:

File 'Controllers/MainController.ts':

class MainController {     ... }  export = MainController; 

File 'Controllers/SecondController.ts':

class SecondController {     ... }  export = SecondController; 

File 'Controllers/Namespace.ts':

import MainController = require('./MainController'); import SecondController = require('./SecondController');  export = { MainController, SecondController } 

File 'App.ts' (where the 'namespace' is used)

import Controllers = require('Controllers/Namespace');  angular.module('app', [])     .controller('MainController', Controllers.MainController)     .controller('SecondController', Controllers.SecondController) 

This gives you nice intellisense, hides the 400 import statements away and keeps the code where the namespace is actually used pretty clean...

like image 187
Wolfgang Avatar answered Oct 16 '22 09:10

Wolfgang


I don't think there is a better way to achieve this with external modules. The language specification defines external modules as follows:

External modules (section 9.4) are separately loaded bodies of code referenced using external module names. An external module is written as a separate source file that contains at least one import or export declaration.

Further down it says that internal modules are open ended and can extend over multiple files:

Internal modules are “open-ended” and internal module declarations with the same qualified name relative to a common root (as defined in section 2.2) contribute to a single module.

I found no other mentioning of a similar statement for external modules. I'm pretty much convinced it's not. If you need module loading, then you'll have to live with reference paths to access types loaded from different files.

However, for me it sounds like you'd better go for internal modules. Then you can simply spread your module over two files

export module MyClasses { export class A {} } 

and

export module MyClasses { export class B {} } 

bring them into scope with reference paths

///<reference path='A.ts'/> ///<reference path='B.ts'/> 

and then simply reference them with the module name such as e.g.

var a = new MyClasses.A(); 
like image 26
Valentin Avatar answered Oct 16 '22 08:10

Valentin