Description
TypeScript Version: nightly (2.2.0-dev.20161127)
EDIT: The issue described below is with --module commonjs
, but as @aluanhaddad points out in a comment below, there are other behaviours with different module emits.
I looked for an existing issue about this but didn't find one. Apologies if this is a duplicate.
I ran into a problem with TypeScript's emit for re-exported bindings, in particular when the original exported value changes over time.
Importing a binding directly from a source module gets a 'live view' that changes when the export value changes, as it should. But importing from a re-exported binding gets a snapshot that is no longer a live view of the original export. This seems not to be spec compliant and leads to my code not working as intended.
Code
// file: a.ts
export let liveView = 'foo';
export function changeTo(val: string) { liveView = val; } // CHANGES THE EXPORT VALUE
// file: b.ts
import {liveView, changeTo} from './a'; // <===== Import directly from A
console.log(liveView); // outputs 'foo'
changeTo('bar');
console.log(liveView); // outputs 'bar' <===== GOOD: binding changed as it should
export {liveView, changeTo} from './a'; // <===== Re-export from A
// file: c.ts
import {liveView, changeTo} from './b'; // <===== Import via B's re-export
console.log(liveView); // outputs 'bar'
changeTo('baz');
console.log(liveView); // outputs 'bar' // <===== BAD: binding is not live anymore
Expected behavior
Emitted code should preserve the live binding to liveView
when re-exporting from b.ts
.
Last line of c.ts
should output 'baz'
.
Actual behavior
Emitted code exports a 'snapshot' of the liveView
binding from b.ts
, so that the import of liveView
into c.ts
is no longer a live binding.
Last line of c.ts
incorrectly outputs 'bar'
.
What should be the Correct Behaviour?
I found it hard to locate a clear description of correct ES6 behaviour for this situation, but from what I did find I think TypeScript's current emit is not compliant with ES6.
-
E.g. from the Exploring ES6 sections about imports as views and about re-exports
-
Babel emits code that preserves the 'live-ness' of re-exports
So for export { liveView } from 'some-module';
TypeScript emits something like:
var some_module_1 = require("some-module");
exports.liveView = some_module_1.liveView;
Whereas babel emits something like:
var _someModule = require('some-module');
Object.defineProperty(exports, 'liveView', {
enumerable: true,
get: function get() {
return _someModule.liveView;
}
});