Skip to content

transpileModule does not elide type only "import equals" #49450

@wnayes

Description

@wnayes

Bug Report

I've encountered a pattern where transpileModule emits unsafe code at runtime, and isolatedModules does not report errors to help catch this case.

Consider the following:

import IInterface = My.Application.Interfaces.IInterface;
export type { IInterface };

Under a "normal" full compile, TypeScript will recognize that IInterface only used as a type, and will essentially emit nothing for either of these lines.

export {};

But when this same snippet is ran through transpileModule, the "import equals" declaration is preserved as a variable.

var IInterface = My.Application.Interfaces.IInterface;
export {};

It isn't safe to assume that My.Application.Interfaces is going to be available at runtime, and this difference could lead to runtime errors.

🔎 Search Terms

isolatedModules import equals namespace type only

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about transpileModule.

⏯ Playground Link

Playground link demonstrating the desired output:
https://www.typescriptlang.org/play?isolatedModules=true&ssl=4&ssc=28&pln=3&pc=1#code/PTAEAEEsGcHsBsCGAXApgEwLK3QV3qtAFyjIBOuqAUFZALYAOsZyoAkmwHZpkBmiAY1SgAvKEwBPAHQBBBg3iQBKSLE5SuPfkOgbNqPoNQBuKqgAeTFqQkNhAb3b7DQ0AF9TVEKAAiqAUhkGKBwdKgA7gAWBsKo8NCoRFTo-oHCAObwsABGiPCg9lSgxaCciGHQDEbi0nIKSipqGtwG2oQFRSVdkC0uwhy9bQVuncUjbkA

Code Sandbox showing the problematic transpileModule behavior:
https://codesandbox.io/s/cocky-mcclintock-9iuqd9?file=/src/index.js

💻 Code

This is essentially what the Code Sandbox is doing:

const result = ts.transpileModule(`
import IInterface = My.Application.Interfaces.IInterface;
export type { IInterface };
`,
  {
    compilerOptions: {
      module: ts.ModuleKind.ESNext
    }
  }
);

🙁 Actual behavior

var IInterface = My.Application.Interfaces.IInterface;
export {};

🙂 Expected behavior

export {};

Suggested Fix

  • Correctly elide the import equals declaration, just like regular import statements.
  • Or protect developers against this runtime risk through an error when isolatedModules is enabled. (However, I don't know of a great replacement for this syntax if this was the direction taken.)

For reference, #45579 was recently fixed, where isolatedModules now reports an error for code like this:

export import JSX = JSXInternal;

It seems to me like developers are going to quickly fix these cases by doing something like this:

import JSX = JSXInternal;
export type { JSX };

And that is the exact pattern I am reporting in this issue.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions