Support TypeScript 4.5 type-only import/export specifiers#13802
Support TypeScript 4.5 type-only import/export specifiers#13802nicolo-ribaudo merged 27 commits intobabel:mainfrom
Conversation
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 1f933af:
|
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/49458/ |
|
I'd personally have preferred if the AST was just |
3cc6c3d to
15392c3
Compare
| @@ -229,9 +229,23 @@ export default declare((api, opts) => { | |||
| continue; | |||
There was a problem hiding this comment.
Can you rebase on latest main? We should also register global type for type-only import specifiers so they can be removed in the following case:
import { type A } from "module";
export { A }15392c3 to
4929209
Compare
nicolo-ribaudo
left a comment
There was a problem hiding this comment.
Can you add a test for import { type A } from "x" with onlyRemoveTypeImports? import "x" should not be removed.
|
|
||
| export function ExportSpecifier(this: Printer, node: t.ExportSpecifier) { | ||
| if (node.exportKind === "type") { | ||
| this.word(node.exportKind); |
There was a problem hiding this comment.
| this.word(node.exportKind); | |
| this.word("type"); |
| } else { | ||
| allElided = false; | ||
| NEEDS_EXPLICIT_ESM.set(path.node, false); | ||
| if (!importsToRemove.includes(binding.path)) { |
There was a problem hiding this comment.
We can use a Set for importsToRemove, since .has() is O(1) while .includes is O(n).
|
@nicolo-ribaudo Thank you for your review! I've addressed your comments. 4d1cde6 |
| } | ||
|
|
||
| if (isAllSpecifiersElided()) { | ||
| if (!onlyRemoveTypeImports && isAllSpecifiersElided()) { |
There was a problem hiding this comment.
Why should we keep import statements when onlyRemoveTypeImports is true?
There was a problem hiding this comment.
@nicolo-ribaudo You said #13802 (review). What do you think?
There was a problem hiding this comment.
Whoops, I assumed that import { type X } from "x" would have been equivalent to import {} from "x" and thus not removed. I'm sorry!
There was a problem hiding this comment.
Hmm, interesting. TS removes import {} from "x", too. It preserves only import "x".
There was a problem hiding this comment.
According to behavior of TypeScript, it is better to remove the Import Statement in such cases. 6b79fd1
| const local = this.parseModuleExportName(); | ||
| node.local = local; | ||
| if (this.eatContextual(tt._as)) { | ||
| node.local = this.parseModuleExportName(); |
There was a problem hiding this comment.
I'd like to avoid mixing TS/flow-specific code in the main parser, when possible.
Would it be possible to move type handling in parseModuleExportName()? Or maybe we reorganize it like this:
parseExportSpecifiers() {
while () { // loop to parse all the specifiers
const local = this.parseModuleExportName();
nodes.push(this.parseExportSpecifier(local));
}
}
parseExportSpecifier(local) {
// ...
}and in typescript/index.js
parseExportSpecifier(local) {
if (local.type === "Identifier" && local.name === "type") {
const node = this.startNodeAtNode(local);
// if this is a type export, parse it as such
return node;
}
return super.parseExprtSpecifier(local);
}This is similar to what we do for imports.
| node[rightOfAsKey] = rightOfAs; | ||
|
|
||
| const kindKey = isImport ? "importKind" : "exportKind"; | ||
| node[kindKey] = hasTypeSpecifier ? "type" : "value"; |
There was a problem hiding this comment.
Can you also update packages/babel-parser/src/types.js?
| // { type as as something } | ||
| hasTypeSpecifier = true; | ||
| leftOfAs = firstAs; | ||
| rightOfAs = this.parseIdentifier(); |
There was a problem hiding this comment.
When we are parsing export, the right-of-as is a liberal identifier (should be parsed by parseIdentifier(true)), otherwise it should throw unexpected reserved word:
export { type a as if } from "x"; // valid
import { type a as if } from "x"; // invalidThere was a problem hiding this comment.
We can use parseIdentifier(true/false) for those specifiers. But Babel doesn't check reserved word for TypeScript. Should we still fix for that?
babel/packages/babel-parser/src/plugins/typescript/index.js
Lines 2237 to 2247 in 248aa9d
There was a problem hiding this comment.
Hmm, let's fix that in another PR, then.
Support type-only import/export specifiers will be landed in TS 4.5.
Todo:
AST change:
/cc @bradzacher What do you think?
importKind: "value" | "type"toImportSpecifier.exportKind: "value" | "type"toExportSpecifierReferences: