TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Hoisted function declarations should be assigned to `exports` before any `require` calls

Open ExE-Boss opened this issue 5 years ago • 1 comments

TypeScript Version: 4.2.0-beta

Search Terms:

  • hoisted function
  • exports hoisted function
  • export hoisted function
  • export hoist function

Code

// @module: CommonJS

// @showEmit
// @showEmittedFile: b.js

// @filename: a.ts
import { b } from "./b.js";

export function a() {
	return b();
}

// @filename: b.ts
import { a } from "./a.js";

// Crashes when transpiled by TypeScript:
a();

export function b() {
	return 123;
}

Workbench Repro

Expected behavior:

The exports.* assignment should be done immediately after __esModule, just like how Babel does it.

// a.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.a = a;
const b_1 = require("./b.js");
function a() {
    return b_1.b();
}

// b.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.b = b;
const a_js_1 = require("./a.js");
// Crashes when transpiled by TypeScript:
a_js_1.a();
function b() {
    return 123;
}

Actual behavior:

The exports assignment is performed after the function declaration, which causes behaviour differences between native ES modules (where hoisted function declarations are initialised before any code begins executing) and transpiled CommonJS modules (where hoisted function declarations are added to the exports object after require(…) calls)

// a.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.a = void 0;
const b_1 = require("./b.js");
function a() {
    return b_1.b();
}
exports.a = a;

// b.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.b = void 0;
const a_js_1 = require("./a.js");
// Crashes when transpiled by TypeScript:
a_js_1.a();
function b() {
    return 123;
}
exports.b = b;

Playground Link: a.js, b.js

Related Issues: https://github.com/microsoft/TypeScript/pull/37093

ExE-Boss avatar Jul 31 '20 20:07 ExE-Boss

:wave: Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the repro in the issue body running against the nightly TypeScript.


Issue body code block by @ExE-Boss

:+1: Compiled
Emit:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.b = void 0;
const a_js_1 = require("./a.js");
// Crashes when transpiled by TypeScript:
(0, a_js_1.a)();
function b() {
    return 123;
}
exports.b = b;

Historical Information
Version Reproduction Outputs
4.4.2, 4.5.2, 4.6.2

:+1: Compiled
Emit:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.b = void 0;
const a_js_1 = require("./a.js");
// Crashes when transpiled by TypeScript:
(0, a_js_1.a)();
function b() {
    return 123;
}
exports.b = b;

4.2.2, 4.3.2

:+1: Compiled
Emit:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.b = void 0;
const a_js_1 = require("./a.js");
// Crashes when transpiled by TypeScript:
a_js_1.a();
function b() {
    return 123;
}
exports.b = b;

typescript-bot avatar Apr 13 '22 23:04 typescript-bot