Skip to content

Type import statement not erased when exported as default #40420

Closed
@peaBerberian

Description

@peaBerberian

TypeScript Version: 4.1.0-dev.20200907

Search Terms: default export type erased

(The keywords I found for that issue are too generic so it may have already been found. Sorry in advance if that is the case.)

Code

I found a strange behavior leading to an error when running the compiled file through node.js. In my [perhaps wrong] opinion, the issue is with how TypeScript compile a TypeScript file to a JS file.

I tried to reduce the issue to the bare minimum. The following code does not anything, but this is the simplification of a problem we encountered in a real bigger codebase.

Let's consider two files:

// exported.ts
type Foo = number;
export { Foo };
// main.ts
import { Foo } from "./exported";
export default Foo;

That's it. Note that there is no importance here that those files only contains types. The same thing happens when real "translate-able" JS code is also there.
The real important part seems to be the export default in main.ts.

Expected behavior:

The expected behavior here is that TypeScript notice that Foo is a type and completely erase it from the resulting JS file.

When compiling with tsc --module es2015 main.ts, I expect to have these two files outputed:

// exported.js

// either nothing, or something like:
export {};
// main.js

// either nothing, or something like:
export {};

And this is exactly what happens if Foo is exported as a named export in main.ts (nothing is written in those files in typescript <= 3.9.7, an empty export for typescript >= 4.0.2).

Actual behavior:

The output from typescript 4.0.2 onward (to 4.1.0-dev.20200907 for my last check) was instead those two files:

// exported.js
export {};
// main.js
import { Foo } from "./exported";

So Foo does have been erased from exported.js but it is kept as an import in main.js for no apparent reason. TypeScript still seems to realize that this is a type that should be erased in main.js as the export clause was removed.

When running the resulting main.js through node (I have to in some way communicate to node that those are ES modules before) I receive the following error:

SyntaxError: The requested module 'file:///exported.js' does not provide an export named 'Foo'

While writing this issue, I saw that an import type statement exists. If I do a import type { Foo } from "./exported"; in main.ts it does work as expected (main.js is now only an export {} statement).
I could stop here and consider this issue as already fixed then.

However, there are two things that makes me think this issue is still one even with that resolution:

  • that import type statement is defined as useful in conditions I did not meet: if you’ve hit issues under --isolatedModules, TypeScript’s transpileModule API, or Babel, this feature might be relevant.
  • older versions of TypeScript (e.g. v3.0.1) work without any problem on that code, and I didn't use any new feature.

Note that I wrote that this is a new issue in TypeScript v4.0.2 onwards but that is not exactly true. The issue exists at least since v3.8.3 (I just know it was not there in v3.0.1) but under another form: in older versions main.js still is the same way but exported.js appears as an empty file. The exact issue I had on my more complex code (strangely) appeared only since updating from v3.9.7 to v4.0.2, so I chose to specifically report this issue it for those new versions.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issueHas ReproThis issue has compiler-backed repros: https://aka.ms/ts-repros

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions