Typescript: ES6 Modules & CommonJS: Re-export with wildcard of export default fails

Created on 12 Apr 2015  路  14Comments  路  Source: microsoft/TypeScript

Not sure this even allowed, but it seems like a reasonable request. Encountered during the transition of require to ES6 modules.
As an example:

Code

Foo.ts

class Foo {}
export default Foo;

Bar.ts

export * from './Foo';

Generated

Foo.js

exports.default = Foo;

Bar.js

function __export(m) {
    for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
__export(require('./Foo'));

Bug

The re-exported object here is now named default.

I assume the following would work:

export {default as Foo} from './Foo'

Or special handling for default:

function __export(m) {
    if ('default' in m) {
        // What name here?
        exports['notDefault'] = m['default'];
        delete m['default'];
    }
    for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
__export(require('./Foo'));
Question

Most helpful comment

export {default as Foo} from './Foo'; should work. my bad for the false alarm.

All 14 comments

looking at the ES6 spec, it should be an error to do that (section 15.2.1.16.3):

If SameValue(exportName, "default") is true, then
a. Assert: A default export was not explicitly defined by this module.
b. Throw a SyntaxError exception.
c. NOTE A default export cannot be provided by an export *

so in this in Bar.ts export * from './Foo'; should have been flagged as an error since module Foo defines a default, and module Bar does not.

@mhegazy Hey thanks for looking at this so quickly and the ES6 section! Kind of interesting this is not applicable. Seemingly the solution is to:

export {default as Foo} from './Foo'

Since the following does not work either:

export Foo from './Foo'

Closing as invalid with ES6 spec. I'll reopen if you want to handle the assertion error.

I will keep it open for the compiler to issue a compile-time warning for this case.

k thanks!

I don't think there is a bug here, nor am I sure a warning is warranted.

In the example above, there is nothing wrong with the export * in Bar.ts and I don't think it should cause a compile-time error or warning. It is perfectly fine for a module Bar.ts to not have a default export and at the same time export * from a module Foo.ts that does have a default export. However, the default export from Foo.ts is ignored by the export * and does not become the default export of Bar.ts (i.e. Bar.ts will have no exported member named default). That is indeed what the compiler does right now, and if you try to import the default export of Bar.ts you'll get an error saying Bar.ts has no default export.

You could perhaps argue our __export helper function should check for and exclude properties named default, but I'm not sure it's worth the overhead. I think the important thing is that we have the correct view of the world in the type checker, and I think we do.

After re-reading the available export schemes of the ES6 spec, I have a much better understanding of what is applicable and agree with you. Exporting is a commonly used language feature, so I wouldn't want to add any degradation in performance because of a spec misunderstanding.

The alternative working solution is slightly documented in the spec, but it is unclear that the word default can be used as the local import identifier name:

export {default as Foo} from './Foo';

I was however able to find a test case tracked within the traceur project doing the same. As long as there is a way to do it :)

Checked with @bterlson and he too thinks that these are illigal:

export { default } from "module2"
export { default as d } from "module2"

The spec is not really clear about these though.

Yeah... I got the idea from the import statement suggested in #2242. It seems to work appropriately.

import { default as Greeter } from "./greeter";
var g = new Greeter();
g.sayHello();

@mhegazy I was about to open a Webstorm bug which is related. Is there a different suggested way to re-export a defaulted local import?

@mtraynham i am not sure i understand the question..

here are few re-export patterns i could think of:

// module.ts
export default class {}
import d from "module";
export default d;
import {default as d } from "module";
export default d;
import {default as d } from "module";
export { d as default};

My fault if I wasn't clear. Import the default of a module and re-export with the same name as module.

Modifying what you have:

import {default as module} from "module";
export {module};

or rather:

import module from "module";
export {module};

Since you suggested that the following might be invalid:

export {default as Foo} from './Foo';

And from this bug, the following does not work:

export Foo from './Foo';

export {default as Foo} from './Foo'; should work. my bad for the false alarm.

Ahh thanks! We can close this as my question has been fully answered :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tenry92 picture tenry92  路  146Comments

RyanCavanaugh picture RyanCavanaugh  路  205Comments

fdecampredon picture fdecampredon  路  358Comments

xealot picture xealot  路  150Comments

nitzantomer picture nitzantomer  路  135Comments