ts-loader: When transpileOnly is enabled, ts-loader leaves in re-exports of types, causing webpack 4 to warn about export not being found

Expected Behaviour

For a project like this:

// bar.ts
export {IFoo, FOO} from "./foo";
export type IBar = {};
// foo.ts
export type IFoo = {};
export const FOO = 1;
// index.ts
import {FOO, IFoo, IBar} from "./bar";

declare function foo(i: number): IFoo;
declare function bar(): IBar;
foo(FOO);
bar();

Regardless of whether transpileOnly is enabled, the output for bar.ts should be (assuming module=ESNEXT):

export var FOO = 1;

Actual Behaviour

The actual output is:

export { IFoo } from "./foo";
export var FOO = 1;

which causes webpack to complain:

WARNING in ./src/bar.ts
1:0-34 "export 'IFoo' was not found in './foo'
 @ ./src/bar.ts
 @ ./src/index.ts

When transpileOnly is off, the module is correctly emitted. This may very well be a compiler bug, but I’m not sure how to use tsc to reproduce this.

Steps to Reproduce the Problem

git clone https://github.com/univerio/ts-loader-type-export-issue
cd ts-loader-type-export-issue
yarn
./node_modules/webpack-cli/bin/webpack.js

Location of a Minimal Repository that Demonstrates the Issue.

https://github.com/univerio/ts-loader-type-export-issue

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 15
  • Comments: 22 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I think I understand it now. I think it has to do with the fact that transpileOnly uses ts.transpileModule, which is essentially equivalent to turning on isolatedModules. When compiling each module separately, the compiler does not have enough information to know whether an import is a type or not (see Microsoft/TypeScript#15231), so while it eliminates imports that are never used in a value position (which works for imported types that are not exported), it cannot know whether an export is a type or not. So, fundamentally, ts.transpileModule is incompatible with type re-exports.

This issue has cropped up now because webpack 4 warns about these invalid exports, but the final bundle otherwise works fine. Perhaps there’s an option in webpack to silence these warnings?

@univerio Oh yes i got it. I’ve set config.module.strictExportPresence = true on webpack config. Thanks a lot!

Found the option:

{
  stats: {
    warningsFilter: /export .* was not found in/,
  }
}

Perhaps we can add it to the readme?

This also works for me and gets the compiler to remove the type export all together:

import { IFoo } from "./foo";
export type IFoo = IFoo;

This is going to be an issue when using any compiler that has to work without having the full type information… like typescript itself in --isolatedModules mode. As long as there is no syntax to annotate type-only exports / reexports this is going to persist as a problem.

^^ To avoid a DenverCoder9 situation, here’s an update.

The example warningsFilter is correct, but if you are working with an ejected create-react-app project, then you need to add this to the build.js script, not to the webpack configuration!

For whatever reason, the warning I posted above is not what you should be basing your regex on. Since the actual warning vs what was being displayed are different strings.

        messages = formatWebpackMessages(
          stats.toJson({
            all: false,
            warnings: true,
            errors: true,
            warningsFilter: [
              /export .* was not found in/
            ]
          })
        );

I’ve reopened this issue following @MLoughry comments on the webpack 5 beta. It seems this issue may present with webpack 5 as maybe an error whereas with webpack 4 it’s a warning.

See https://github.com/webpack/webpack/issues/9802#issuecomment-547161433

If people could detail:

  1. What they’re experiencing
  2. If there are any remedies

That would be helpful. It’s not clear to me that the problems being experienced can be solved by ts-loader. Any “fix” would likely need to be implemented within the TypeScript APIs or handled by webpack configuration.

I’m reopening this ticket for visibility and in the hope that people can use this as a place to discuss the issues. If people could comment that would be amazing.

As it is, ts-loader is a bridge between webpack and TypeScript. It can’t (I think) solve the problem of differing needs / aims which this change in approach by webpack represents. But hopefully it can encourage discussion and collaboration between the two 🤗

cc @andrewbranch @sokra

That did not work for me, but the solution in https://github.com/babel/babel-loader/issues/603#issuecomment-418472968 did:

import { T as a_T } from "./a";
export type T = a_T;