Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused about TypeScript modules

I'm new to TypeScript but have a background in C# and I'm a little bit confused about how to handle TypeScript modules. I've been thinking about modules as namespaces in C# but maybe this is wrong because my code doesn't behave the way I was expecting.

I have the following folder structure:

|-myApp
|  |-myController
|  |      |-myController.ts
|  |-models
       |-a.ts
       |-b.ts

and this code:

// a.ts
module MyApp.Models {
    export class A {

    }
}
// b.ts
module MyApp.Models {
    export class B {

    }
}

// myController.ts (THIS DOESN'T WORK)
module MyApp.MyController {
    import Models = MyApp.Models;
    class MyController {
        a = new Models.A();
        b = new Models.B();
    }
}

// myController.ts (THIS WORKS)
module MyApp.MyController {
    class MyController {
        a = new Models.A();
        b = new Models.B();
    }
}

In the example above my attempt at importing the module (namespace?) Models will result in an error at runtime because Models is undefined. However if I remove the import-statement the code will works just fine. I'm probably not thinking clearly and doing some really stupid beginners mistake but could someone please tell me what I'm doing wrong and what the best way to use modules in my particular scenario would be. Why does it work if I remove the import but not with it?

Regards Kristofer

like image 585
Kristofer Avatar asked Sep 26 '15 17:09

Kristofer


People also ask

What are modules in TypeScript?

In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module. Conversely, a file without any top-level import or export declarations is treated as a script whose contents are available in the global scope (and therefore to modules as well).

What is the difference between namespace and modules in TypeScript?

1. 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. 2.

What is the difference between internal and external modules in TypeScript?

Internal modules are declared using ModuleDeclarations that specify their name and body. A name path with more than one identifier is equivalent to a series of nested internal module declarations. External modules (section 9.4) are separately loaded bodies of code referenced using external module names.

Does TypeScript use ES6 modules?

TypeScript 1.5 supports ECMAScript 6 (ES6) modules. ES6 modules are effectively TypeScript external modules with a new syntax: ES6 modules are separately loaded source files that possibly import other modules and provide a number of externally accessible exports.


1 Answers

Sorry for late answer.

Problem and magic around modules/namespaces are occurred in three things:

  1. Your system - due to your system TypeScript compiler discover files by difference ways, and when it compile your source code to JS code it take a place, because the same ts files provide different results JS.
  2. Understanding magic statement /// <reference path="***"/>. It is very important use this word if there are no additional Module System like AMD, or System.js, etc. Because if you use merged compilation it take place, because it tell compiler in what order it should compile files.
  3. Understanding of JS execution and structure that TypeScript propose in compiled JS file. Just consider next example - (it is your compiled into JS example)

        var MyApp;
        (//functon wrapping
         function (MyApp) {//function declaration 
            var MyController;
            (function (MyController_1) {
                var Models = MyApp.Models;
                var MyController = (function () {
                    function MyController() {
                        this.a = new Models.A();
                        this.b = new Models.B();
                    }
                    return MyController;
                })();
                MyController_1.MyController = MyController;
            })(MyController = MyApp.MyController || (MyApp.MyController = {}));
        }
        )(MyApp || (MyApp = {}));// end of function wrapping and it execution
        /// <reference path="myApp/MyController/myController.ts"/>
    
        new MyApp.MyController.MyController(); // createing new instance of MyController
    
        var MyApp;
        (function (MyApp) {
            var Models;
            (function (Models) {
                var B = (function () {
                    function B() {
                    }
                    return B;
                })();
                Models.B = B;
            })(Models = MyApp.Models || (MyApp.Models = {}));
        })(MyApp || (MyApp = {}));
        var MyApp;
        (function (MyApp) {
            var Models;
            (function (Models) {
                var A = (function () {
                    function A() {
                    }
                    return A;
                })();
                Models.A = A;
            })(Models = MyApp.Models || (MyApp.Models = {}));
        })(MyApp || (MyApp = {}));
        //# sourceMappingURL=app.js.map
    

    if you dive deeper into JS you would find that the JS code is executing in the next order

    • Reading function and passing it into the memory
    • Executing another code

    That is why the next code would work

     myFunction();
    
     function myFunctuion(){};
    

    Due to typescript JS building technics for modules and classes it use anonimous function like this:

    var MyApp;
        (//functon wrapping
         function (MyApp) {//function declaration 
            var MyController;
            (function (MyController_1) {
                var Models = MyApp.Models;
                var MyController = (function () {
                    function MyController() {
                        this.a = new Models.A();
                        this.b = new Models.B();
                    }
                    return MyController;
                })();
                MyController_1.MyController = MyController;
            })(MyController = MyApp.MyController || (MyApp.MyController =  {}));
    

    In this case calling like next cause runtime exception, because anonimus block has not executed before.

      MyController(); // here runtime exception
    
      var MyController = (function () {
                    function MyController() {
                        this.a = new Models.A();
                        this.b = new Models.B();
                    }
                    return MyController;
                })();
    

    Now, back to the our example and discover it, as you see MyController defined earlier, than we do execution of anonymous function and variable with name MyController now exist in the global scope. The next step is executing constructor of MyController class, in it we find next two part of code

           this.a = new Models.A();
           this.b = new Models.B();
    

    But here we get an error because the anonymous function that consist variable Modules and classes A and B has not executed yet. That is why, in this moment we getting the error that variable Modules is undefined.

I hope that this topic make your knowledge about JS and TS better, and help you in your new features!!!

Good Luck!

P.S. Here is working example

like image 102
Oleh Dokuka Avatar answered Oct 14 '22 07:10

Oleh Dokuka