The article discusses the resolution of a Webpack warning related to missing exports in a TypeScript project using TypeScript 3.8's new feature of type-only imports and exports.
Abstract
The author of the article encountered a puzzling issue where Webpack warned about missing exports despite the exports being present in the TypeScript code. This problem arose due to the nature of TypeScript's transpilation process, which erases types during compilation, leading to non-existent imports in the emitted JavaScript files. The article traces the author's journey from confusion to understanding, culminating in the discovery of TypeScript 3.8's feature that allows for type-only imports and exports. This feature enabled the author to specify that certain imports are used exclusively as types, instructing the TypeScript compiler to omit them from the final JavaScript output, thereby resolving the Webpack warnings. The author emphasizes the utility of this new TypeScript feature in providing more granular control over the compilation process and suggests it as a solution for similar edge cases.
Opinions
The author initially felt puzzled and ashamed about the issue, especially after publishing a book on TypeScript.
Tobias Koppers was credited with quickly identifying the core of the problem.
The author expresses enthusiasm about the TypeScript 3.8 release and its resolution to the import issue they faced.
A warning is given to readers to use the new feature judiciously and not to overuse it.
The author sees the new TypeScript feature as a significant enhancement, providing finer control and addressing annoying edge cases.
The author recommends their book and newsletter subscription for learning more about TypeScript and related technologies.
Leveraging Type-Only imports and exports with TypeScript 3.8
A few months back, I started seeing strange warnings in Webpack about exports that couldn’t be found.
I was puzzled. Obviously, there was something wrong, since the export was really there:
And I couldn’t notice what was wrong where I was using that type:
The thing is that once TypeScript code is transpiled, interfaces/types are gone. They don’t exist anymore; they don’t exist in the emitted files.
What I didn’t think much about before is that while the types are erased, the imports/exports aren’t necessarily. The reason is that there are ambiguities and that the compiler doesn’t always know for sure whether something that is exported is a type or a value.
In my particular case, what Webpack saw when it processed the resulting JavaScript code is that an import was there for something that didn’t exist.
Webpack was lenient, so it only emitted a warning, but the issue was indeed really there and I had no control over what TypeScript generated in that case.
TypeScript 3.8 to the rescue
I didn’t have much time to look further into the issue at that point, so I let it rest for a while (it wasn’t blocking), but later, once TypeScript 3.8 was released, I noticed something really interesting in the release notes: Type-Only Imports and Exports.
It directly reminded me of my import issue…
This new feature of TypeScript added the possibility to import an element only as a type, precisely for cases where a type is imported only to be used as a type and never as a value. And this was exactly what I needed; thanks to this I could finally tell the compiler precisely what I wanted to do.
Well, as the TS release notes explain, by importing an element using “import type”, it tells the compiler that the element is only imported to be used as a type annotation/declaration. Thanks to this, the compiler knows that it can erase the import in the emitted code.
With this single change done, Webpack was immediately happier: no more weird imports!
Note that you can also use “export type” to indicate that some export will only ever be used as a type annotation/declaration.
Finally, the behavior can be further configured through the “importsNotUsedAsValues” flag.
Conclusion
TypeScript Type-Only imports/exports are a useful addition to the language, allowing us to have more fine-grained control over what TypeScript does for us, hence allowing us to handle some annoying “edge cases” like this one.
A word of warning though: don’t go overboard with this ;-)
PS: If you want to learn tons of other cool things about TypeScript, Angular, React, Vue and other cool subjects, then don’t hesitate to grab a copy of my book and to subscribe to my newsletter!