microsoft/TypeScript

Separate Module ID from type information location

Closed this issue · 2 comments

Here is a pattern I use in my unit tests all the time:

import MyModule = module("../../../../Web/Scripts/SubComponent/MyModule");
declare module 'app/SubComponent/MyModule' { };
import _m = module('app/SubComponent/MyModule');
var m = <MyModule>_m;

describe( "MyModule", () => {
    it( "should be awesome", () => {
        m.someFunc();
    });
});

Note how I'm using one module import to get type information and another module import to get the compiler to generate the appropriate define call, and then I tie the two together with a typecast.

This happens because RequireJS running in the browser disagrees with the TypeScript compiler on where the module is located. For RequireJS, the module's location gets remapped first through IIS and then through RequireJS's own config, while the compiler sees bare file system.

Contrary to the first obvious objection some people would have, this situation is not always avoidable. I've been able to dance around it within the actual project (so far), but with unit tests there is no luck: I can't put both "test" and "app" modules in the same location on the file system, but they have to appear so to the browser that is running the tests.

So wouldn't it be wonderful if the compiler allowed me to specify these two values (type info vs. module ID) separately?
Something like:

import MyModule = module('app/SubComponent/MyModule') from('../../../../Web/Scripts/SubComponent/MyModule.ts')

From comments on CodePlex:

@lukehoban:
Interesting work around, I don't think I realized that would have worked.

I suspect the most likely approach we would take to addressing this is do something more similar to what requires and other loaders do at runtime - provide a way to configure how paths get (re)routed at compilation time, so that you can match this up with what's happening at runtime, or use a different file system structure at compile time vs runtime. I suspect we would keep this configuration information outside of the source files themselves, and have it be something separate passed to the compiler. We haven't thought deeply about what this would need to look like yet though. If you have thoughts on what this should look like, feel free to share in comments here.

@fsoikin:
Thank you for the reply. Glad I could interest you with my hacking practices :-)

I am slightly concerned with the "separate config" approach, because it would require passing parameters to the compiler.
I work in Visual Studio using your plugin for Intellisense support and WebEssentials for compile-on-save functionality. Both of these will need to get the location of the config from somewhere. I guess a custom project property page should work... Right?

As far as the format of the config itself, I personally think JSON is the only sane answer.
And then the most popular AMD loader out there already has a pretty well-defined and widely used format, so why reinvent the wheel?

I'm not sure about Node (not much of a node developer), but it would appear to me that Node doesn't have a config at all, does it? It just assumes this directory structure with node_modules/[module]/package.json and goes from there. Right?

Tagging Needs Proposal and In Discussion - we need to determine a better story for configurable module resolution

This should be achievable today with #5039. please reopen if there are additional requirements.