54

Closed

Allow module.exports

description

As discussed here (http://stackoverflow.com/questions/12696236/module-exports-in-typescript), it would be a very handy feature if exports like the following:
export class Greeter {}
compiles to:
module.exports = Greeter; or exports = Greeter;
Closed Jun 17, 2013 at 4:42 PM by LukeH
This is available as "export =" in TypeScript 0.9.

comments

jonturner wrote Oct 4, 2012 at 4:07 AM

Thanks for the suggestion.

delaaxe wrote Oct 4, 2012 at 2:24 PM

I'm using this pattern in all my codebase, and I think I'm not the only one. I'd really like to see this possible.
Maybe allow syntax like

exports = class Greeter {}

once class expressions will be supported.

KerstenB wrote Oct 4, 2012 at 2:48 PM

Yes, that was my attempted too. Most of the libraries I am using are working like this and not the way as it is now.

damassi wrote Oct 5, 2012 at 7:28 PM

Just ran into this yesterday. All of my files use this pattern and currently it breaks in TypeScript / not backwards compatible.

rwaldron wrote Oct 7, 2012 at 12:02 AM

I think module could be declared in a .d.ts file, with an exports property... Haven't tried it, but worth a shot

rwaldron wrote Oct 7, 2012 at 12:06 AM

I should have noted that this is absolutely possible because module{} syntax is contextual with a look ahead for the curlies

rwaldron wrote Oct 7, 2012 at 12:19 AM

dcstraw wrote Oct 18, 2012 at 6:44 PM

I agree that this is an important feature. I have existing JavaScript code that exposes exports that are meant to be used like a base class, i.e. you call {exportname}.apply(this, ...). Currently I can't use TypeScript's class concept to interop with this code but classes would be perfect for this.

rwaldron wrote Oct 18, 2012 at 7:38 PM

@dcstraw To take full advantage of TypeScript, you should probably re-factor those to be actual modules with class definitions that are inherited with "extends" and use "super()" instead of "the old fashioned way"

dcstraw wrote Oct 18, 2012 at 9:04 PM

@rwaldron agreed but in this case I don't control the code I'm calling, and it's probably not going to be converted to TypeScript any time soon. I'm treating that code much like any other JavaScript library, and I'm providing .d.ts files to add typing information.

dallonf wrote Nov 9, 2012 at 7:59 PM

This is seriously blocking backwards compatibility for my team (deployd.com). We'd love to write a TypeScript definition file for extensions, but we use module.exports all over the code base and it's impossible to write the subclasses our API depends on with wrapping them in a JavaScript file that uses the "exports" pattern instead.

damassi wrote Nov 12, 2012 at 1:21 AM

Perhaps this should be elevated a bit higher than 'impact: low' because this is a WIDELY used design pattern that completely breaks old code.

rwaldron wrote Nov 12, 2012 at 4:19 AM

I imagine this could happen, but only as an optional tsc compile flag. Anything else is breaking the line between language and library.

LukeH wrote Nov 29, 2012 at 1:05 AM

EisenbergEffect wrote Jan 3, 2013 at 3:43 AM

This is a serious blocking issue. It is an extremely common practice to export a constructor function as a module's export. The original ES6 module spec didn't allow this, but they have made some improvements and now it does...along with a few other changes. TypeScript should be synced up with the improved module spec as soon as possible to enable compatibility with ES6 and enable this key scenario.

LukeH wrote Jan 3, 2013 at 11:48 PM

@EisenbergEffect - definitely understood that this limits some significant module usage patterns. The ES6 syntax and semantics for this feature are still in some flux, and we are working with the TC39 group on getting this part of the ES6 proposal stabilized as soon as possible. As soon as this looks stable, we fully expect to add "export =" style syntax as in ES6.

EisenbergEffect wrote Jan 21, 2013 at 8:25 PM

Thanks for the update Luke!

TimSpeed wrote Mar 1, 2013 at 4:50 PM

  • Bump :P
    This is essential to develop nicely structured code in node
    Change things around so that only one export is allowed at the global level.
    This can be either a class or module
    Exporting a module would give the same effect we have now
export module "server" {
    export class ResponseHandler ...
    export class Server ...
}
And to make things even nicer it should accept referencing of files with the same exported module
Then everything would merge, similar to the internal module design pattern, except one could actually import things in referenced files.
for example Server.ts:
/// <reference path="./Net.Server.ts" />
/// <reference path="./Net.ResponseHandler.ts" />
export module "Net" {
    export var CONNECTION_TIMEOUT = 20000;
}
Net.Server.ts
/// <reference path="./node.d.ts" />
/// <reference path="./Net.ResponseHandler.ts" />
import http = module('http');

export module "Net" {
    export class Server ...
}
... Oh if only :)

LukeH wrote Mar 10, 2013 at 2:57 AM

@TimSpeed - Indeed, we are working on a syntax for enabling this in the current 0.9 branch. The specification draft in the "doc" folder there now includes an "export =" declaration (section 9.2.1) that would provide basic support for modules representing single value exports. More work in spec drafts and implementation on the way soon.

blittle wrote Mar 25, 2013 at 9:07 PM

Definite +1 on implementing this. Generally it is best practice for a module to do one thing and one thing only, which in many cases translates to exporting only one item. If only one is exported, why not have that directly be the exports object? Then the whole file can be named the exports module, example:

Telescope.ts
export class Telescope {}
Observatoroy.ts
import Telescope = module('Telescope');
var telescope = new Telescope.Telescope();
Wouldn't something like this look nicer?

Telescope.ts
exports = class Telescope {}
Observatoroy.ts
import Telescope = module('Telescope');
var telescope = new Telescope();

PulsarBlow wrote Apr 13, 2013 at 2:06 AM

+1, this is really much needed.

Scriby wrote Apr 17, 2013 at 5:11 AM

+1, ran into this last night when trying to convert a project over to using TypeScript

jonturner wrote Apr 26, 2013 at 10:52 PM

We're looking into this for 0.9.

The gist for the feature is that you will be able to "export = symbolName" and that would export the namespace/type/value information for that symbol name.
//fileA.ts
class Telescope { ... }
export = Telescope;

//fileB.ts
import Tele = require("fileA.ts");
var tele = new Tele();

anurse wrote May 16, 2013 at 7:37 PM

@jonturner - Is this in the 0.9 preview? I'm trying to use it and getting "tsc.js(689, 13) Microsoft JScript runtime error: please implement in derived class" from the compiler. If it's not there, that's OK, but I'd like to add another vote for making sure it makes it in to 0.9 :)

bmantuano wrote May 23, 2013 at 6:22 PM

Another vote from me. This would be a huge help.

Doing this would allow existing require.js-style class modules to be refactored into TypeScript without having to simultaneously refactor every single place where that module is used. This allows the upgrade path to TypeScript be an on-demand one, rather than an all-at-once ordeal.

The simplicity from not having to write module.class everywhere is also a big plus.

On this note, is there an interim workaround that allows you to create a reference to module.class and use that down the line?
Using the telescope example from above:
import TelescopeModule = module('Telescope');
var Telescope = TelescopeModule.Telescope;
var tele = new Telescope();  // compiles and validates, but no code hinting
var tele2: Telescope = new Telescope(); // "The name 'Telescope' does not exist in the current scope"

aaronshaf wrote May 29, 2013 at 6:07 PM

Please put this in 0.9.

jonturner wrote May 29, 2013 at 7:27 PM

@aaronshaf - if you're able, you can download the 0.9 compiler that's currently in-progress and try out the "export = " support. The associated spec, I believe, also talks about it, but in general you can put an "export = <symbol name>" in a module in place of exporting separate symbols and when you later import, the import will pull in all the value/type/namespace information of the associated symbol.

It's like module.export =, but it works with all the types and namespace goodness of TypeScript.

aaronshaf wrote May 29, 2013 at 7:53 PM

jonturner, thanks much!

aaronshaf wrote May 29, 2013 at 7:55 PM

jonturner, this is huge -- you should make a note of this in a blog post.

wiktork wrote Jun 15, 2013 at 12:51 PM

export = symbol works as advertised but I found minor issue if the exported symbol is generic. It seems the typescript compiler is treating is as private.

Steps to reproduce, two files:

bar.js:
class Bar<T> {
    public z: T;
}

export = Bar;
foo.js:
import Bar = module("./bar");

export class Foo {
    public m: Bar<string>;
}
Compiling with tsc --module amd bar.ts foo.ts generates the following error:
foo.ts(4,5): error TS2025: Public property 'm' of exported class has or is using private type 'Bar<string>'.

Bar should be treated as public because it is exported. I'm using beta version of tsc: Version 0.9.0.0.

aaronshaf wrote Jun 19, 2013 at 4:41 PM

@jonturner, can you provide a simple example of how one would use this in a node.js app?