Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use typeof for an ambient external module type. #2346

Closed
rotemdan opened this issue Mar 13, 2015 · 3 comments
Closed

Can't use typeof for an ambient external module type. #2346

rotemdan opened this issue Mar 13, 2015 · 3 comments

Comments

@rotemdan
Copy link

I need to get type information for a CommonJS module that's dynamically (and sometimes conditionally) loaded within the scope of an internal module. Some background on why this is important (and the hoops I go through to work around this restriction today) here: #2327 (comment)

(TL;DR: my current workaround is to transform the external module declaration file to an internal module declaration file, using several regular expressions, here's one I did for node.d.ts (with the RegExps I used in the comments): https://github.com/rotemdan/lzutf8.js/blob/master/LZUTF8/Library/Dependencies/node-internal.d.ts)

This works (with correct intellisense):

declare module InternalModule
{
    export var member: number;
}

module Test
{
    var internalModuleInstance: typeof InternalModule = SomeInternalModule;
}

But this:

declare module "ExternalModule"
{
    export var member: number;
}

module Test
{
    var externalModuleInstance: typeof ExternalModule = require("SomeExternalModule");
}

or even this:

declare module "ExternalModule"
{
    export var member: number;
}

var externalModuleInstance: typeof ExternalModule = require("SomeExternalModule");

Results in

Error: Cannot find name 'ExternalModule'
@rotemdan
Copy link
Author

I found this in the handbook:
http://www.typescriptlang.org/Handbook#modules-optional-module-loading-and-other-advanced-loading-scenarios

It says that import x = require("y") will not emit anything unless referenced in a value position. Well I assumed that using the keyword require would immediately translate to an actual call to require but apparently I was wrong? So quite unexpectedly:

ExternalModule.d.ts:

declare module "ExternalModule"
{
    export var member: number;
}

App.ts

import ExternalModule = require("ExternalModule");

module Test
{
      if (false)
          var externalModuleInstance: typeof ExternalModule = require("SomeExternalModule");
}

emits

var Test;
(function (Test) {
    if (false)
        var externalModuleInstance = require("SomeExternalModule");
})(Test || (Test = {}));

Seems like import can be used to only import the type (when only use in a type position) but if used as a value would import the module itself. I'm not sure how many TypeScript developers are actually aware of this (perhaps this feature was added, or at least documented, only recently?) as this is quite an ambiguous use of both the keyword import and require.

I would have still found it easier to naturally apply typeof to the ambient type itself. I do realize there might be an technical issue with parsing its identifier (having external module names in quotes perhaps means they could have spaces, start with digits etc. and can't really be used as identifiers). I'm not sure if the syntax chosen is great but it least I've found a way to make it work.

@danquirk
Copy link
Member

Seems like import can be used to only import the type (when only use in a type position) but if used as a value would import the module itself. I'm not sure how many TypeScript developers are actually aware of this (perhaps this feature was added, or at least documented, only recently?) as this is quite an ambiguous use of both the keyword import and require.

You're definitely not the first to be bitten by this. It is subtle but there are good reasons for it. We've recently been talking about potential alternatives to make this scenario easier/clearer.

@rotemdan
Copy link
Author

Hi, thanks for your reply! It's not every day that I discover a way to do something that I thought was impossible for literally years now.

EDIT: I opened a new issue with a proposal for an alternative syntax: #2357.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants