microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.93k stars 12.47k forks source link

__importStar sometimes inlined when using dynamic imports with --importHelpers #27415

Open dgoldstein0 opened 6 years ago

dgoldstein0 commented 6 years ago

TypeScript Version: 3.1.1

Search Terms: __importStar tslib

Code a.ts:

import('b').then(b => console.log(b));

compile with

tsc a.ts --esModuleInterop --importHelpers

Expected behavior: some type errors, but emitted code should require("tslib") and use __importStar from there

Actual behavior: some type errors and generated code looks like this:

var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
Promise.resolve().then(function () { return __importStar(require('b')); }).then(function (b) { return console.log(b); });

btw an example that works correctly:

import('c').then(b => console.log(b));

class Foo {}

export class Bar extends Foo {}

both the extends and the export seem to be necessary

Playground Link: N/A (--esModuleInterop doesn't exist in the playground)

Related Issues: This is basically #21560 but replacing regular imports with dynamic imports

luke-lacroix-healthy commented 2 years ago

I'm seeing the same thing. Typescript is emitting several helpers in a source file that has only type imports and a dynamic import. If I combine importHelpers with noEmitHelpers, Typescript actually outputs bad JS because it references __importStar which isn't defined.

Example source:

import type * as yargs from 'yargs';

const commandModule: yargs.CommandModule = {
    builder: {},
    command: 'scan <path>',
    handler: (argv) => {
        const {scan} = await import('../impl/scan');
        await scan(argv);
    }
}

module.exports = commandModule;

Output (importHelpers: true, noEmitHelpers: false):

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const commandModule = {
    builder:  {},
    command: 'scan <path>',
    describe: 'scan a workspace for licenses',
    handler: async (argv) => {
        const { scan } = await Promise.resolve().then(() => __importStar(require('../impl/scan')));
        await scan(argv);
    },
};
module.exports = commandModule;
//# sourceMappingURL=scan.js.map

Expected output:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const commandModule = {
    builder:  {},
    command: 'scan <path>',
    describe: 'scan a workspace for licenses',
    handler: async (argv) => {
        const { scan } = await Promise.resolve().then(() => tslib_1.__importStar(require('../impl/scan')));
        await scan(argv);
    },
};
module.exports = commandModule;
//# sourceMappingURL=scan.js.map

If I change import type * as yargs from 'yargs' to import * as yargs from 'yargs' and use values from the module, then it correctly imports the helpers. If I only use types from the module, then it still erases the import an emits the helpers.