Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
ExE-Boss opened this issue Jul 31, 2020 · 1 comment · Fixed by #57669
Closed
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@ExE-Boss
Copy link
Contributor

ExE-Boss commented Jul 31, 2020

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: #37093

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Aug 17, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.1.0 milestone Aug 17, 2020
@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Dec 11, 2020
@typescript-bot typescript-bot added the Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros label Feb 11, 2021
@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 13, 2022

👋 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

👍 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

👍 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

👍 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;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants