Skip to content

Inconsistency between named exports when targetting ES2015: export const foo = bar and export {bar as foo} #23804

@AlCalzone

Description

@AlCalzone

TypeScript Version: 2.8.3, 2.9.0-dev.20180501

Search Terms: name export const

When conditionally assigning to variables that are exported later, the emitted output is inconsistent. In my case I was polyfilling functionality not present in older NodeJS versions through an external module.
The emitted output had a weird order, so when the external module was loaded, I actually exported undefined.

Code
target: es2015

export interface Foo {
	method: (...args: any[]) => void;
}

declare function internal(): void;

let exportedFoo: Foo;

declare const condition: boolean;
if (condition) {
	// Use native method
	exportedFoo = {
		method: internal,
	};
} else {
	// Use polyfilled method
	({ foo: exportedFoo } = require("some-module")); // [1]
}

export { exportedFoo as foo }; // [2]

Expected behavior:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
let exportedFoo;
if (condition) {
    // Use native method
    exportedFoo = {
        method: internal,
    };
}
else {
    // Use polyfilled method
    ({ foo: exportedFoo } = require("some-module"));
}
exports.foo = exportedFoo;

Actual behavior:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
let exportedFoo;
exports.foo = exportedFoo;
if (condition) {
    // Use native method
    exports.foo = exportedFoo = {
        method: internal,
    };
}
else {
    // Use polyfilled method
    ({ foo: exportedFoo } = require("some-module"));
}

If condition is true, the export works as expected. Otherwise, exports.foo is undefined.

There are two ways to fix the output:

  • changing line [1] to exportedFoo = require("some-module").foo; but this duplicates the assignment to exports.foo (one per if/else branch)
  • changing line [2] to export const foo = exportedFoo;, this leads to the expected output

The TypeScript Playground seems to get it right however...

Playground Link: https://www.typescriptlang.org/play/#src=export%20interface%20Foo%20%7B%0D%0A%09method%3A%20(...args%3A%20any%5B%5D)%20%3D%3E%20void%3B%0D%0A%7D%0D%0A%0D%0Adeclare%20function%20internal()%3A%20void%3B%0D%0A%0D%0Alet%20exportedFoo%3A%20Foo%3B%0D%0A%0D%0Adeclare%20const%20condition%3A%20boolean%3B%0D%0Aif%20(condition)%20%7B%0D%0A%09%2F%2F%20Use%20native%20method%0D%0A%09exportedFoo%20%3D%20%7B%0D%0A%09%09method%3A%20internal%2C%0D%0A%09%7D%3B%0D%0A%7D%20else%20%7B%0D%0A%09%2F%2F%20Use%20polyfilled%20method%0D%0A%09(%7B%20foo%3A%20exportedFoo%20%7D%20%3D%20require(%22some-module%22))%3B%0D%0A%7D%0D%0A%0D%0Aexport%20%7B%20exportedFoo%20as%20foo%20%7D%3B%0D%0A

Related Issues: ?

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions