Skip to content

ES Module imports discarded when they include a type and a side-effect #28285

Closed

Description

When an ES module syntax import has an explicit type and a side effect it is excluded from the output JS.

TypeScript Version: 3.2.0-dev.20181101

Search Terms:

  • ES Modules
  • Module resolution

Code

  • tsconfig.json target ESNext
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext"
  }
}
  • source-component.ts with an export and a side effect
export class SourceComponent extends HTMLElement {
    // Web component implementation   
}
customElements.define('source-component', SourceComponent);
  • missing-import.ts that references the dependency as a type and expects the side effect
import {SourceComponent} from './source-component.js';
const example = document.createElement('source-component') as SourceComponent;

Expected behaviour:

When output to missing-import.js the reference should be retained:

import {SourceComponent} from './source-component.js';
const example = document.createElement('source-component');

An import as a side effect would be acceptable too:

import './source-component.js';
const example = document.createElement('source-component');

Actual behaviour:

The import is stripped out:

const example = document.createElement('source-component');

Workaround:
Duplicate side effect import statements are retained:

import {SourceComponent} from './source-component.js';
import './source-component.js';
const example = document.createElement('source-component') as SourceComponent;

Activity

  1. weswigham commented on Nov 1, 2018

    @weswigham
    Member

    Duplicate of #9191 I imagine.

  2. KeithHenry commented on Nov 1, 2018

    @KeithHenry
    Author

    Wesley Wigham (@weswigham) Certainly looks like it, only this is explicit ESNext modules and #9191 is referencing require - I assume that means a fix for require would be a fix for ESNext modules?

    Only require is doing some mapping and ES Modules aren't - I think there's potentially a much easier fix for this as for ESNext modules in TS you have to include the .js suffix, so:

    import { MyComponent } from './my-component'; // gets definition from my-component.d.ts
    import { OtherComponent } from './other-component.js'; // doesn't need to check, always include in JS output
    

    #9191 has been sitting round for years without a fix because finding out whether the reference includes a side effect is incredibly difficult.

    However this could be fixed by adding a special case for ESNext when an explicit .js file extension is present.

    As a fix for this wouldn't necessarily be a fix for #9191 does this still count as a duplicate? Especially as #9191 is never going to get fixed (require will get deprecated first) and ES Modules will become the standard?

  3. weswigham commented on Nov 1, 2018

    @weswigham
    Member

    Even if the import includes .js extension, we still look up an associated .d.ts file, and you might still only use the types from it. The presence of an extension doesn't change anything, really.

  4. KeithHenry commented on Nov 3, 2018

    @KeithHenry
    Author

    Wesley Wigham (@weswigham) yes, so for TS the extension is optional, but for JS missing the extension will throw an error. The only reason to include the extension in TS is because you want the import to work in the JS output, and in that case you always want to retain it.

    Imports with explicit .js extensions should always be in the output.

  5. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions