Skip to content

Commit 2080042

Browse files
airatonicolo-ribaudo
authored andcommitted
fix(typescript): erase type exports (#9944)
* fix(typescript): erase type exports * use Set instead of array for tracking and checking TS type declarations * add a test for an interface exported before its declaration
1 parent 3f0590d commit 2080042

File tree

3 files changed

+129
-0
lines changed

3 files changed

+129
-0
lines changed

packages/babel-plugin-transform-typescript/src/index.js

+61
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,22 @@ function isInType(path) {
1616
}
1717
}
1818

19+
function isTSExportableDeclaration(node) {
20+
// all kinds of type exports that transpile to nothing
21+
// exception is enums, since they transpile to JS values
22+
return (
23+
t.isTSInterfaceDeclaration(node) ||
24+
t.isTSTypeAliasDeclaration(node) ||
25+
t.isTSModuleDeclaration(node) ||
26+
(t.isVariableDeclaration(node) && node.declare) ||
27+
(t.isClassDeclaration(node) && node.declare) ||
28+
t.isTSDeclareFunction(node)
29+
);
30+
}
31+
1932
interface State {
2033
programPath: any;
34+
exportableTSNames: Set<string>;
2135
}
2236

2337
const PARSED_PARAMS = new WeakSet();
@@ -40,6 +54,7 @@ export default declare((api, { jsxPragma = "React" }) => {
4054

4155
Program(path, state: State) {
4256
state.programPath = path;
57+
state.exportableTSNames = new Set();
4358

4459
const { file } = state;
4560

@@ -52,6 +67,32 @@ export default declare((api, { jsxPragma = "React" }) => {
5267
}
5368
}
5469

70+
// find exportable top level type declarations
71+
for (const stmt of path.get("body")) {
72+
if (isTSExportableDeclaration(stmt.node)) {
73+
if (stmt.node.id && stmt.node.id.name) {
74+
state.exportableTSNames.add(stmt.node.id.name);
75+
} else if (
76+
stmt.node.declarations &&
77+
stmt.node.declarations.length > 0
78+
) {
79+
for (const declaration of stmt.node.declarations) {
80+
if (declaration.id && declaration.id.name) {
81+
state.exportableTSNames.add(declaration.id.name);
82+
}
83+
}
84+
}
85+
} else if (
86+
t.isExportNamedDeclaration(stmt.node) &&
87+
stmt.node.specifiers.length === 0 &&
88+
isTSExportableDeclaration(stmt.node.declaration) &&
89+
stmt.node.declaration.id &&
90+
stmt.node.declaration.id.name
91+
) {
92+
state.exportableTSNames.add(stmt.node.declaration.id.name);
93+
}
94+
}
95+
5596
// remove type imports
5697
for (const stmt of path.get("body")) {
5798
if (t.isImportDeclaration(stmt)) {
@@ -94,6 +135,26 @@ export default declare((api, { jsxPragma = "React" }) => {
94135
}
95136
},
96137

138+
ExportNamedDeclaration(path, { exportableTSNames }) {
139+
// remove export declaration if it's exporting only types
140+
if (
141+
path.node.specifiers.length > 0 &&
142+
!path.node.specifiers.find(
143+
exportSpecifier =>
144+
!exportableTSNames.has(exportSpecifier.local.name),
145+
)
146+
) {
147+
path.remove();
148+
}
149+
},
150+
151+
ExportSpecifier(path, { exportableTSNames }) {
152+
// remove type exports
153+
if (exportableTSNames.has(path.node.local.name)) {
154+
path.remove();
155+
}
156+
},
157+
97158
TSDeclareFunction(path) {
98159
path.remove();
99160
},

packages/babel-plugin-transform-typescript/test/fixtures/declarations/erased/input.mjs

+37
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,40 @@ declare namespace N {}
88
export interface I {}
99
export type T = number;
1010
export class C2 {}
11+
12+
export { x, f, E, C }; // only E
13+
export { M, N, I as I1, T as T1 }; // everything removed
14+
export {
15+
x as x2,
16+
f as f2,
17+
C as CC2,
18+
E as E2,
19+
M as M2,
20+
N as N2,
21+
I as I2,
22+
T as T2,
23+
C2 as C3
24+
}; // only E and C2
25+
26+
interface II2 {}
27+
type AA = {};
28+
enum BB {
29+
K
30+
}
31+
enum BB {
32+
L = "LL"
33+
}
34+
export { II2, AA, BB }; // only BB
35+
export { II2 as II3, AA as AA2 }; // everything removed
36+
export { BB as BB1 }; // as-is
37+
38+
interface II3 {}
39+
type AA2 = {};
40+
enum BB2 {}
41+
function foo() {}
42+
export { II3 as default, AA2 as A, BB2 as BB3, foo }; // only BB2 and foo
43+
44+
// export an interface before declaration
45+
export { Bar } // everything removed
46+
export { Bar as Bar2, C2 as C4 } // only C4
47+
interface Bar {}
Original file line numberDiff line numberDiff line change
@@ -1 +1,32 @@
11
export class C2 {}
2+
export { E }; // only E
3+
4+
// everything removed
5+
export { E as E2, C2 as C3 }; // only E and C2
6+
7+
var BB;
8+
9+
(function (BB) {
10+
BB[BB["K"] = 0] = "K";
11+
})(BB || (BB = {}));
12+
13+
(function (BB) {
14+
BB["L"] = "LL";
15+
})(BB || (BB = {}));
16+
17+
export { BB }; // only BB
18+
19+
// everything removed
20+
export { BB as BB1 }; // as-is
21+
22+
var BB2;
23+
24+
(function (BB2) {})(BB2 || (BB2 = {}));
25+
26+
function foo() {}
27+
28+
export { BB2 as BB3, foo }; // only BB2 and foo
29+
// export an interface before declaration
30+
31+
// everything removed
32+
export { C2 as C4 }; // only C4

0 commit comments

Comments
 (0)