Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript: Multiple projects in solution

Tags:

typescript

I've finished porting a JavaScript library to TypeScript in Visual Studio 2012. All in all its about 60 classes, with each class defined in its own .ts file.

All classes are defined in the same module. I use reference comments to reder to classes defined in other files. The layout of every file looks like this:

///<reference path='./../myotherclass.ts' />

module MyModule {

    export class MyClass {
        ...
    }

}

Now I've created a second project in the same solution which is going to be the actual application using my newly ported library. I have to include my library somehow and I guess that's what the module system is for. However, I'm not sure what file(s) to import as MyModule is spread over dozens of files. Is this what I can use the .d.ts file for?

Also, to be able to import a module, it has to be declared with the 'export' keyword but if I do that then it is not found by reference comments anymore.

On top of all that, both projects should be compiled so that the compiler output can be readily used with a module loader like requireJS.

What's the best approach to accomplish all this?

Thank you!

like image 293
vexator Avatar asked Oct 07 '12 15:10

vexator


1 Answers

Ok, so let me begin by saying that "Module" can mean different things. For example, there is the "module pattern" which is what your "MyModule" creates. As far as I gather, TypeScript refers to these as "Internal Modules" in the language spec, and these differ from "External Modules" that you would be loading with something like RequireJS. The main distinction is that external modules expect to have their own isolated environment with a predefined 'exports' object they can use for exporting their functionality.

Take a look at the output of your module:

var MyModule;
(function (MyModule) {
    var MyClass = (function () {
        function MyClass() { }
        return MyClass;
    })();
    MyModule.MyClass = MyClass;    
})(MyModule || (MyModule = {}));

You see that it is exporting things into "MyModule" which will be made globally available to other script files you load with, for example, an html "script" block. Being that you mentioned you have 60 of these, you could probably also set the compiler to output a single file that you could include in markup, instead of loading each file one by one.

Moving on, take a look at what happens to the output if you change your module declaration from "module MyModule { ... }" to "export module MyModule { ... }":

(function (MyModule) {
    var MyClass = (function () {
        function MyClass() { }
        return MyClass;
    })();
    MyModule.MyClass = MyClass;    
})(exports.MyModule || (exports.MyModule = {}));

As you see, your module is still using the "module pattern" but it is being assigned to as a member of "exports", signifying that it is meant to be loaded with, for example, node's "require" function.

In this case, you would want to actually use your module with this code:

import wrapper = module("./MyModule");
var instance = new wrapper.MyModule.MyClass();

Note the "./MyModule" name actually refers to the filename (minus the .js extension) the module is defined in (this is why VS was saying it couldn't find those modules for you). The code should compile to something like:

var wrapper = require("./MyModule");
var instance = new wrapper.MyModule.MyClass();

To add to this, you no longer even really need to do anything with the "module" keyword to have a module. You could simply export a function:

// foo.ts
export function foo() {
    ...
};

// some other file in the same dir
import wrapper = module("./foo");
var result = wrapper.foo();

This works because the function 'foo' will be directly assigned to "exports" which will be aliased to "wrapper" in the other file.

To add further onto this confusing mess of module related things, I should also mention that AMD modules are different still because they are loaded asynchronously, unlike node's "require". To get TypeScript to output those you'll need to pass in a "--module AMD" parameter to the compiler.

Anyway, I hope I explained the situation well enough to the point you'll be able to figure out what exactly you need/want. The type of modules you end up using will really depend on how you'll be using them... i.e., node, web, or some mix of both.

like image 121
nxn Avatar answered Oct 28 '22 23:10

nxn