From b28f427c41f4d5c99a817e9ff85ce31e16a2dfc2 Mon Sep 17 00:00:00 2001
From: Jack Works <5390719+Jack-Works@users.noreply.github.com>
Date: Fri, 18 Apr 2025 01:07:53 +0800
Subject: [PATCH 1/2] fix: private field in class expression emits invalid dts

---
 src/compiler/checker.ts                       |  4 +-
 ...assExpressionInDeclarationFile2.errors.txt | 12 ++-
 .../emitClassExpressionInDeclarationFile2.js  | 84 ++++++++-----------
 ...tClassExpressionInDeclarationFile2.symbols | 13 +++
 ...mitClassExpressionInDeclarationFile2.types | 23 +++++
 .../emitClassExpressionInDeclarationFile2.ts  |  7 ++
 6 files changed, 90 insertions(+), 53 deletions(-)

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index d96b4907df565..f6628484a7e98 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -7485,8 +7485,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                         if (propertySymbol.flags & SymbolFlags.Prototype) {
                             continue;
                         }
-                        if (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected) && context.tracker.reportPrivateInBaseOfClassExpression) {
+                        if (context.tracker.reportPrivateInBaseOfClassExpression && (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected))) {
                             context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName));
+                        } else if (context.tracker.reportPrivateInBaseOfClassExpression && isHashPrivate(propertySymbol)) {
+                            context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(getClonedHashPrivateName(propertySymbol)?.escapedText || '' as __String));
                         }
                     }
                     if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) {
diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.errors.txt b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.errors.txt
index e755cfdfa259b..17ee33446ebf0 100644
--- a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.errors.txt
+++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.errors.txt
@@ -2,9 +2,10 @@ emitClassExpressionInDeclarationFile2.ts(1,12): error TS4094: Property 'p' of ex
 emitClassExpressionInDeclarationFile2.ts(1,12): error TS4094: Property 'ps' of exported anonymous class type may not be private or protected.
 emitClassExpressionInDeclarationFile2.ts(16,17): error TS4094: Property 'property' of exported anonymous class type may not be private or protected.
 emitClassExpressionInDeclarationFile2.ts(23,14): error TS4094: Property 'property' of exported anonymous class type may not be private or protected.
+emitClassExpressionInDeclarationFile2.ts(30,12): error TS4094: Property '#p' of exported anonymous class type may not be private or protected.
 
 
-==== emitClassExpressionInDeclarationFile2.ts (4 errors) ====
+==== emitClassExpressionInDeclarationFile2.ts (5 errors) ====
     export var noPrivates = class {
                ~~~~~~~~~~
 !!! error TS4094: Property 'p' of exported anonymous class type may not be private or protected.
@@ -43,4 +44,13 @@ emitClassExpressionInDeclarationFile2.ts(23,14): error TS4094: Property 'propert
     
     Test.getTags()
     test.tags();
+    
+    export var noPrivates2 = class {
+               ~~~~~~~~~~~
+!!! error TS4094: Property '#p' of exported anonymous class type may not be private or protected.
+!!! related TS9027 emitClassExpressionInDeclarationFile2.ts:30:12: Add a type annotation to the variable noPrivates2.
+        static getTags() { }
+        tags() { }
+        #p = -1
+    }
     
\ No newline at end of file
diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.js b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.js
index 7448d7496af59..f3b4331ef8c5c 100644
--- a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.js
+++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.js
@@ -29,72 +29,54 @@ const test = new Test();
 
 Test.getTags()
 test.tags();
+
+export var noPrivates2 = class {
+    static getTags() { }
+    tags() { }
+    #p = -1
+}
 
 
 //// [emitClassExpressionInDeclarationFile2.js]
-"use strict";
-var __extends = (this && this.__extends) || (function () {
-    var extendStatics = function (d, b) {
-        extendStatics = Object.setPrototypeOf ||
-            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
-            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
-        return extendStatics(d, b);
-    };
-    return function (d, b) {
-        if (typeof b !== "function" && b !== null)
-            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
-        extendStatics(d, b);
-        function __() { this.constructor = d; }
-        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
-    };
-})();
 var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
     if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
     return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
 };
-var _a;
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.Test = exports.FooItem = exports.noPrivates = void 0;
-exports.WithTags = WithTags;
-exports.noPrivates = (_a = /** @class */ (function () {
-        function class_1() {
+var _a, _noPrivates2_p, _b;
+export var noPrivates = (_a = class {
+        constructor() {
             this.p = 12;
         }
-        class_1.getTags = function () { };
-        class_1.prototype.tags = function () { };
-        return class_1;
-    }()),
+        static getTags() { }
+        tags() { }
+    },
     __setFunctionName(_a, "noPrivates"),
     _a.ps = -1,
     _a);
 // altered repro from #15066 to add private property
-var FooItem = /** @class */ (function () {
-    function FooItem() {
+export class FooItem {
+    constructor() {
         this.property = "capitalism";
     }
-    FooItem.prototype.foo = function () { };
-    return FooItem;
-}());
-exports.FooItem = FooItem;
-function WithTags(Base) {
-    return /** @class */ (function (_super) {
-        __extends(class_2, _super);
-        function class_2() {
-            return _super !== null && _super.apply(this, arguments) || this;
-        }
-        class_2.getTags = function () { };
-        class_2.prototype.tags = function () { };
-        return class_2;
-    }(Base));
+    foo() { }
 }
-var Test = /** @class */ (function (_super) {
-    __extends(Test, _super);
-    function Test() {
-        return _super !== null && _super.apply(this, arguments) || this;
-    }
-    return Test;
-}(WithTags(FooItem)));
-exports.Test = Test;
-var test = new Test();
+export function WithTags(Base) {
+    return class extends Base {
+        static getTags() { }
+        tags() { }
+    };
+}
+export class Test extends WithTags(FooItem) {
+}
+const test = new Test();
 Test.getTags();
 test.tags();
+export var noPrivates2 = (_b = class {
+        constructor() {
+            _noPrivates2_p.set(this, -1);
+        }
+        static getTags() { }
+        tags() { }
+    },
+    _noPrivates2_p = new WeakMap(),
+    _b);
diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.symbols b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.symbols
index 167ec73bdbabc..c4c6827dca66d 100644
--- a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.symbols
+++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.symbols
@@ -75,3 +75,16 @@ test.tags();
 >test : Symbol(test, Decl(emitClassExpressionInDeclarationFile2.ts, 24, 5))
 >tags : Symbol((Anonymous class).tags, Decl(emitClassExpressionInDeclarationFile2.ts, 17, 34))
 
+export var noPrivates2 = class {
+>noPrivates2 : Symbol(noPrivates2, Decl(emitClassExpressionInDeclarationFile2.ts, 29, 10))
+
+    static getTags() { }
+>getTags : Symbol(noPrivates2.getTags, Decl(emitClassExpressionInDeclarationFile2.ts, 29, 32))
+
+    tags() { }
+>tags : Symbol(noPrivates2.tags, Decl(emitClassExpressionInDeclarationFile2.ts, 30, 24))
+
+    #p = -1
+>#p : Symbol(noPrivates2.#p, Decl(emitClassExpressionInDeclarationFile2.ts, 31, 14))
+}
+
diff --git a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.types b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.types
index b0365b56e6053..2b1571627332f 100644
--- a/tests/baselines/reference/emitClassExpressionInDeclarationFile2.types
+++ b/tests/baselines/reference/emitClassExpressionInDeclarationFile2.types
@@ -116,3 +116,26 @@ test.tags();
 >tags : () => void
 >     : ^^^^^^    
 
+export var noPrivates2 = class {
+>noPrivates2 : typeof noPrivates2
+>            : ^^^^^^^^^^^^^^^^^^
+>class {    static getTags() { }    tags() { }    #p = -1} : typeof noPrivates2
+>                                                          : ^^^^^^^^^^^^^^^^^^
+
+    static getTags() { }
+>getTags : () => void
+>        : ^^^^^^^^^^
+
+    tags() { }
+>tags : () => void
+>     : ^^^^^^^^^^
+
+    #p = -1
+>#p : number
+>   : ^^^^^^
+>-1 : -1
+>   : ^^
+>1 : 1
+>  : ^
+}
+
diff --git a/tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts b/tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts
index 3175f2afce7df..ae572352fd123 100644
--- a/tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts
+++ b/tests/cases/compiler/emitClassExpressionInDeclarationFile2.ts
@@ -1,4 +1,5 @@
 // @declaration: true
+// @target: ES6
 export var noPrivates = class {
     static getTags() { }
     tags() { }
@@ -27,3 +28,9 @@ const test = new Test();
 
 Test.getTags()
 test.tags();
+
+export var noPrivates2 = class {
+    static getTags() { }
+    tags() { }
+    #p = -1
+}

From d6c7a6c9da8e6df78a612dd4e1ecd23c113fb673 Mon Sep 17 00:00:00 2001
From: Jack Works <5390719+Jack-Works@users.noreply.github.com>
Date: Fri, 18 Apr 2025 01:12:08 +0800
Subject: [PATCH 2/2] fix: format

---
 src/compiler/checker.ts | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index f6628484a7e98..61d93328c50cb 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -7487,8 +7487,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                         }
                         if (context.tracker.reportPrivateInBaseOfClassExpression && (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected))) {
                             context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName));
-                        } else if (context.tracker.reportPrivateInBaseOfClassExpression && isHashPrivate(propertySymbol)) {
-                            context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(getClonedHashPrivateName(propertySymbol)?.escapedText || '' as __String));
+                        }
+                        else if (context.tracker.reportPrivateInBaseOfClassExpression && isHashPrivate(propertySymbol)) {
+                            context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(getClonedHashPrivateName(propertySymbol)?.escapedText || "" as __String));
                         }
                     }
                     if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) {