Repository: babel/babel (TypeScript)

Issue:
[Feature Request] TypeScript make generated codes from enum could be minified when not used
## Feature Request

**Is your feature request related to a problem? Please describe.**

For now TypeScript will transform enum from

```ts
enum Test {
    Key = 1
}
```
to

```ts
var Test;
(function (Test) {
    Test[Test["Key"] = 1] = "Key";
})(Test || (Test = {}));
```
This result is not friendly for uglyify or tree-shaking.
When `Test` is not be used, the generated code block always remain as dead codes.

**Describe the solution you'd like**

prefer to generate codes below:
```ts
var Test = /*#__PURE__*/(function () {
    var e = {}
    e[e["Key"] = 1] = "Key";
    return e
})();
```
![image](https://user-images.githubusercontent.com/1667873/46602882-0d778d00-cb24-11e8-8847-cbb3483e0960.png)

The suggestion version will be removed.

related: https://github.com/Microsoft/TypeScript/issues/27604
custom plugin: https://github.com/morlay/babel-plugin-typescript-iife-enum


Hints:
Hey @morlay! We really appreciate you taking the time to report an issue. The collaborators
on this project attempt to help as many people as possible, but we're a limited number of volunteers,
so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant [Slack
community](https://babeljs.slack.com) that typically always has someone willing to help. You can sign-up [here](https://slack.babeljs.io/)
for an invite.

Patch:
diff --git a/packages/babel-plugin-transform-typescript/src/enum.ts b/packages/babel-plugin-transform-typescript/src/enum.ts
--- a/packages/babel-plugin-transform-typescript/src/enum.ts
+++ b/packages/babel-plugin-transform-typescript/src/enum.ts
@@ -1,16 +1,26 @@
 import { template, types as t } from "@babel/core";
 import type { NodePath } from "@babel/traverse";
 import assert from "assert";
+import annotateAsPure from "@babel/helper-annotate-as-pure";
 
 type t = typeof t;
 
 const ENUMS = new WeakMap<t.Identifier, PreviousEnumMembers>();
 
+const buildEnumWrapper = template.expression(
+  `
+    (function (ID) {
+      ASSIGNMENTS;
+      return ID;
+    })(INIT)
+  `,
+);
+
 export default function transpileEnum(
   path: NodePath<t.TSEnumDeclaration>,
   t: t,
 ) {
-  const { node } = path;
+  const { node, parentPath } = path;
 
   if (node.declare) {
     path.remove();
@@ -18,24 +28,41 @@ export default function transpileEnum(
   }
 
   const name = node.id.name;
-  const { wrapper: fill, data } = enumFill(path, t, node.id);
+  const { fill, data, isPure } = enumFill(path, t, node.id);
 
-  switch (path.parent.type) {
+  switch (parentPath.type) {
     case "BlockStatement":
     case "ExportNamedDeclaration":
     case "Program": {
-      path.insertAfter(fill);
-      if (seen(path.parentPath)) {
-        path.remove();
+      // todo: Consider exclude program with import/export
+      // && !path.parent.body.some(n => t.isImportDeclaration(n) || t.isExportDeclaration(n));
+      const isGlobal = t.isProgram(path.parent);
+      const isSeen = seen(parentPath);
+
+      let init: t.Expression = t.objectExpression([]);
+      if (isSeen || isGlobal) {
+        init = t.logicalExpression("||", t.cloneNode(fill.ID), init);
+      }
+      const enumIIFE = buildEnumWrapper({ ...fill, INIT: init });
+      if (isPure) annotateAsPure(enumIIFE);
+
+      if (isSeen) {
+        const toReplace = parentPath.isExportDeclaration() ? parentPath : path;
+        toReplace.replaceWith(
+          t.expressionStatement(
+            t.assignmentExpression("=", t.cloneNode(node.id), enumIIFE),
+          ),
+        );
       } else {
-        // todo: Consider exclude program with import/export
-        // && !path.parent.body.some(n => t.isImportDeclaration(n) || t.isExportDeclaration(n));
-        const isGlobal = t.isProgram(path.parent);
         path.scope.registerDeclaration(
-          path.replaceWith(makeVar(node.id, t, isGlobal ? "var" : "let"))[0],
+          path.replaceWith(
+            t.variableDeclaration(isGlobal ? "var" : "let", [
+              t.variableDeclarator(node.id, enumIIFE),
+            ]),
+          )[0],
         );
-        ENUMS.set(path.scope.getBindingIdentifier(name), data);
       }
+      ENUMS.set(path.scope.getBindingIdentifier(name), data);
       break;
     }
 
@@ -57,16 +84,6 @@ export default function transpileEnum(
   }
 }
 
-function makeVar(id: t.Identifier, t: t, kind: "var" | "let" | "const") {
-  return t.variableDeclaration(kind, [t.variableDeclarator(id)]);
-}
-
-const buildEnumWrapper = template(`
-  (function (ID) {
-    ASSIGNMENTS;
-  })(ID || (ID = {}));
-`);
-
 const buildStringAssignment = template(`
   ENUM["NAME"] = VALUE;
 `);
@@ -83,7 +100,7 @@ const buildEnumMember = (isString: boolean, options: Record<string, unknown>) =>
  * `(function (E) { ... assignments ... })(E || (E = {}));`
  */
 function enumFill(path: NodePath<t.TSEnumDeclaration>, t: t, id: t.Identifier) {
-  const { enumValues: x, data } = translateEnumValues(path, t);
+  const { enumValues: x, data, isPure } = translateEnumValues(path, t);
   const assignments = x.map(([memberName, memberValue]) =>
     buildEnumMember(t.isStringLiteral(memberValue), {
       ENUM: t.cloneNode(id),
@@ -93,11 +110,12 @@ function enumFill(path: NodePath<t.TSEnumDeclaration>, t: t, id: t.Identifier) {
   );
 
   return {
-    wrapper: buildEnumWrapper({
+    fill: {
       ID: t.cloneNode(id),
       ASSIGNMENTS: assignments,
-    }),
-    data: data,
+    },
+    data,
+    isPure,
   };
 }
 
@@ -141,10 +159,11 @@ export function translateEnumValues(path: NodePath<t.TSEnumDeclaration>, t: t) {
   // Start at -1 so the first enum member is its increment, 0.
   let constValue: number | string | undefined = -1;
   let lastName: string;
+  let isPure = true;
 
-  return {
-    data: seen,
-    enumValues: path.get("members").map(memberPath => {
+  const enumValues: Array<[name: string, value: t.Expression]> = path
+    .get("members")
+    .map(memberPath => {
       const member = memberPath.node;
       const name = t.isIdentifier(member.id) ? member.id.name : member.id.value;
       const initializerPath = memberPath.get("initializer");
@@ -161,6 +180,8 @@ export function translateEnumValues(path: NodePath<t.TSEnumDeclaration>, t: t) {
             value = t.stringLiteral(constValue);
           }
         } else {
+          isPure &&= initializerPath.isPure();
+
           if (initializerPath.isReferencedIdentifier()) {
             ReferencedIdentifier(initializerPath, {
               t,
@@ -197,7 +218,12 @@ export function translateEnumValues(path: NodePath<t.TSEnumDeclaration>, t: t) {
 
       lastName = name;
       return [name, value];
-    }) as Array<[name: string, value: t.Expression]>,
+    });
+
+  return {
+    isPure,
+    data: seen,
+    enumValues,
   };
 }
 


Test patch:
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/output.js
@@ -1,5 +1,5 @@
 // Not type-correct code
-var E;
-(function (E) {
+var E = /*#__PURE__*/function (E) {
   E[E["A"] = true] = "A";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/output.js
@@ -1,3 +1,4 @@
 // With --isolatedModules, TSC ignores the "const" modifier when compiling enums
-var E;
-(function (E) {})(E || (E = {}));
+var E = /*#__PURE__*/function (E) {
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/output.js
@@ -1,5 +1,4 @@
-var E;
-(function (E) {
+var E = /*#__PURE__*/function (E) {
   E[E["a"] = 0] = "a";
   E[E["b"] = 3] = "b";
   E[E["c"] = 1] = "c";
@@ -18,4 +17,5 @@ var E;
   E[E["p"] = -3] = "p";
   E[E["q"] = 5.4] = "q";
   E[E["r"] = 6.4] = "r";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/export/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/enum/export/output.mjs
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/export/output.mjs
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/export/output.mjs
@@ -1,7 +1,8 @@
-export let E;
-(function (E) {
+export let E = /*#__PURE__*/function (E) {
   E[E["A"] = 1] = "A";
-})(E || (E = {}));
-(function (E) {
+  return E;
+}({});
+E = /*#__PURE__*/function (E) {
   E[E["B"] = 2] = "B";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/output.js
@@ -1,5 +1,5 @@
-var E;
-(function (E) {
+var E = /*#__PURE__*/function (E) {
   E[E["x"] = 0] = "x";
   E[E["y"] = 1] = "y";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/output.js
@@ -1,5 +1,5 @@
-var E;
-(function (E) {
+var E = /*#__PURE__*/function (E) {
   E[E["a"] = 10] = "a";
   E[E["b"] = 10] = "b";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/output.js
@@ -1,25 +1,24 @@
 var x = 10;
-var Foo;
-(function (Foo) {
+var Foo = /*#__PURE__*/function (Foo) {
   Foo[Foo["a"] = 10] = "a";
   Foo[Foo["b"] = 10] = "b";
   Foo[Foo["c"] = 20] = "c";
-})(Foo || (Foo = {}));
-var Bar;
-(function (Bar) {
+  return Foo;
+}(Foo || {});
+var Bar = function (Bar) {
   Bar[Bar["D"] = 10] = "D";
   Bar[Bar["E"] = 10] = "E";
   Bar[Bar["F"] = Math.E] = "F";
   Bar[Bar["G"] = 30] = "G";
-})(Bar || (Bar = {}));
-var Baz;
-(function (Baz) {
+  return Bar;
+}(Bar || {});
+var Baz = function (Baz) {
   Baz[Baz["a"] = 0] = "a";
   Baz[Baz["b"] = 1] = "b";
   Baz[Baz["x"] = Baz.a.toString()] = "x";
-})(Baz || (Baz = {}));
-var A; // a refers to A.a
-(function (A) {
+  return Baz;
+}(Baz || {});
+var A = function (A) {
   A[A["a"] = 0] = "a";
   A[A["b"] = (() => {
     let a = 1;
@@ -28,4 +27,5 @@ var A; // a refers to A.a
   A[A["c"] = (() => {
     return A.a + 2;
   })()] = "c";
-})(A || (A = {}));
+  return A;
+}(A || {}); // a refers to A.a
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/output.js
@@ -1,5 +1,5 @@
-var E;
-(function (E) {
+var E = function (E) {
   E[E["a"] = Math.sin(1)] = "a";
   E[E["b"] = 1 + E["a"]] = "b";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/output.js
@@ -1,8 +1,9 @@
-var E;
-(function (E) {
+var E = /*#__PURE__*/function (E) {
   E[E["x"] = 1] = "x";
   E[E["y"] = 2] = "y";
-})(E || (E = {}));
-(function (E) {
+  return E;
+}(E || {});
+E = /*#__PURE__*/function (E) {
   E[E["z"] = 3] = "z";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/output.js
@@ -1,14 +1,14 @@
-var socketType;
-(function (socketType) {
+var socketType = /*#__PURE__*/function (socketType) {
   socketType[socketType["SOCKET"] = 0] = "SOCKET";
   socketType[socketType["SERVER"] = 1] = "SERVER";
   socketType[socketType["IPC"] = 2] = "IPC";
-})(socketType || (socketType = {}));
-var constants;
-(function (constants) {
+  return socketType;
+}(socketType || {});
+var constants = /*#__PURE__*/function (constants) {
   constants[constants["SOCKET"] = 0] = "SOCKET";
   constants[constants["SERVER"] = 1] = "SERVER";
   constants[constants["IPC"] = 2] = "IPC";
   constants[constants["UV_READABLE"] = 3] = "UV_READABLE";
   constants[constants["UV_WRITABLE"] = 4] = "UV_WRITABLE";
-})(constants || (constants = {}));
+  return constants;
+}(constants || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/scoped/output.js
@@ -1,5 +1,6 @@
 {
   // Uses 'let' within a scope
-  let E;
-  (function (E) {})(E || (E = {}));
+  let E = /*#__PURE__*/function (E) {
+    return E;
+  }({});
 }
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/output.js
@@ -1,4 +1,4 @@
-var E;
-(function (E) {
+var E = /*#__PURE__*/function (E) {
   E["A"] = "Hey";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/output.js
@@ -1,7 +1,7 @@
-var E;
-(function (E) {
+var E = /*#__PURE__*/function (E) {
   E[E["A"] = 0] = "A";
   E["B"] = "";
   E[E["A2"] = 0] = "A2";
   E["B2"] = "";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/output.js
@@ -1,4 +1,4 @@
-var E;
-(function (E) {
+var E = /*#__PURE__*/function (E) {
   E["A"] = "HALLOWERLD";
-})(E || (E = {}));
+  return E;
+}(E || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/output.js
--- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/output.js
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/output.js
@@ -2,18 +2,18 @@
 
 const BaseValue = 10;
 const Prefix = "/data";
-var Values; // 12
-(function (Values) {
+var Values = /*#__PURE__*/function (Values) {
   Values[Values["First"] = 10] = "First";
   Values[Values["Second"] = 11] = "Second";
   Values[Values["Third"] = 12] = "Third";
-})(Values || (Values = {}));
+  return Values;
+}(Values || {}); // 12
 const xxx = 100 + Values.First;
 const yyy = xxx;
-var Routes;
-(function (Routes) {
+var Routes = /*#__PURE__*/function (Routes) {
   Routes["Parts"] = "/data/parts";
   Routes["Invoices"] = "/data/invoices";
   Routes["x"] = "10/x";
   Routes["y"] = "110/y";
-})(Routes || (Routes = {}));
+  return Routes;
+}(Routes || {});
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/exports/declared-types/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/exports/declared-types/output.mjs
--- a/packages/babel-plugin-transform-typescript/test/fixtures/exports/declared-types/output.mjs
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/exports/declared-types/output.mjs
@@ -1,19 +1,21 @@
 export class C2 {}
 // everything removed
 export { C2 as C3 }; // only C2->C3
-var BB;
-(function (BB) {
+var BB = /*#__PURE__*/function (BB) {
   BB[BB["K"] = 0] = "K";
-})(BB || (BB = {}));
-(function (BB) {
+  return BB;
+}(BB || {});
+BB = /*#__PURE__*/function (BB) {
   BB["L"] = "LL";
-})(BB || (BB = {}));
+  return BB;
+}(BB || {});
 export { BB }; // only BB
 
 // everything removed
 export { BB as BB1 }; // BB->BB1
-var BB2;
-(function (BB2) {})(BB2 || (BB2 = {}));
+var BB2 = /*#__PURE__*/function (BB2) {
+  return BB2;
+}(BB2 || {});
 function foo() {}
 export { BB2 as BB3, foo }; // only BB2->BB3 and foo
 
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/exports/export-const-enums/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/exports/export-const-enums/output.mjs
--- a/packages/babel-plugin-transform-typescript/test/fixtures/exports/export-const-enums/output.mjs
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/exports/export-const-enums/output.mjs
@@ -1,4 +1,5 @@
-var None;
-(function (None) {})(None || (None = {}));
+var None = /*#__PURE__*/function (None) {
+  return None;
+}(None || {});
 ;
 export {};
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-id/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-id/output.mjs
--- a/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-id/output.mjs
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-id/output.mjs
@@ -1,6 +1,6 @@
-var Enum;
-(function (Enum) {
+var Enum = /*#__PURE__*/function (Enum) {
   Enum[Enum["A"] = 0] = "A";
-})(Enum || (Enum = {}));
+  return Enum;
+}(Enum || {});
 ;
 export {};
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-value/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-value/output.mjs
--- a/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-value/output.mjs
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-value/output.mjs
@@ -1,6 +1,6 @@
 import { A } from 'lib';
-var Enum;
-(function (Enum) {
+var Enum = /*#__PURE__*/function (Enum) {
   Enum[Enum["id"] = A] = "id";
-})(Enum || (Enum = {}));
+  return Enum;
+}(Enum || {});
 ;
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs
--- a/packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs
@@ -1,7 +1,7 @@
-var A;
-(function (A) {
+var A = /*#__PURE__*/function (A) {
   A[A["C"] = 2] = "C";
-})(A || (A = {}));
+  return A;
+}(A || {});
 (function (_A) {
   const B = _A.B = 1;
 })(A || (A = {}));
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/namespace/nested/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/namespace/nested/output.mjs
--- a/packages/babel-plugin-transform-typescript/test/fixtures/namespace/nested/output.mjs
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/namespace/nested/output.mjs
@@ -14,20 +14,20 @@ class A {}
   _A.D = D;
   (function (_D) {
     const C = 5;
-    let H;
-    (function (H) {
+    let H = /*#__PURE__*/function (H) {
       H[H["I"] = 11] = "I";
       H[H["J"] = 13] = "J";
       H[H["K"] = 17] = "K";
-    })(H || (H = {}));
+      return H;
+    }({});
     _D.H = H;
   })(D || (D = _A.D || (_A.D = {})));
   class F {}
   (function (_F) {})(F || (F = {}));
   let G;
   (function (_G) {})(G || (G = {}));
-  let L;
-  (function (L) {
+  let L = /*#__PURE__*/function (L) {
     L[L["M"] = 19] = "M";
-  })(L || (L = {}));
+    return L;
+  }({});
 })(A || (A = {}));
diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/namespace/same-name/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/namespace/same-name/output.mjs
--- a/packages/babel-plugin-transform-typescript/test/fixtures/namespace/same-name/output.mjs
+++ b/packages/babel-plugin-transform-typescript/test/fixtures/namespace/same-name/output.mjs
@@ -12,8 +12,9 @@ let N;
     _N8._N5 = _N5;
   })(N || (N = _N2.N || (_N2.N = {})));
   (function (_N9) {
-    let _N;
-    (function (_N) {})(_N || (_N = {}));
+    let _N = /*#__PURE__*/function (_N) {
+      return _N;
+    }({});
     _N9._N = _N;
   })(N || (N = _N2.N || (_N2.N = {})));
 })(N || (N = {}));
diff --git a/packages/babel-preset-typescript/test/fixtures/flow-compat/ts-valid/output.js b/packages/babel-preset-typescript/test/fixtures/flow-compat/ts-valid/output.js
--- a/packages/babel-preset-typescript/test/fixtures/flow-compat/ts-valid/output.js
+++ b/packages/babel-preset-typescript/test/fixtures/flow-compat/ts-valid/output.js
@@ -1,5 +1,5 @@
-var Example;
-(function (Example) {
+var Example = /*#__PURE__*/function (Example) {
   Example[Example["Value"] = 0] = "Value";
-})(Example || (Example = {}));
+  return Example;
+}(Example || {});
 foo;
diff --git a/packages/babel-preset-typescript/test/fixtures/flow-compat/tsx-valid/output.js b/packages/babel-preset-typescript/test/fixtures/flow-compat/tsx-valid/output.js
--- a/packages/babel-preset-typescript/test/fixtures/flow-compat/tsx-valid/output.js
+++ b/packages/babel-preset-typescript/test/fixtures/flow-compat/tsx-valid/output.js
@@ -1,5 +1,5 @@
-var Example;
-(function (Example) {
+var Example = /*#__PURE__*/function (Example) {
   Example[Example["Value"] = 0] = "Value";
-})(Example || (Example = {}));
+  return Example;
+}(Example || {});
 foo;