Fix private identifier fields generating errors in class expression declarations (#62155)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: weswigham <2932786+weswigham@users.noreply.github.com>
Co-authored-by: Wesley Wigham <wewigham@microsoft.com>
Co-authored-by: TypeScript Bot <typescriptbot@microsoft.com>
This commit is contained in:
Copilot 2025-07-31 15:51:51 -07:00 committed by GitHub
parent c3ee238ae7
commit 39c5d01877
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 180 additions and 0 deletions

View File

@ -710,6 +710,7 @@ import {
isPrivateIdentifier,
isPrivateIdentifierClassElementDeclaration,
isPrivateIdentifierPropertyAccessExpression,
isPrivateIdentifierSymbol,
isPropertyAccessEntityNameExpression,
isPropertyAccessExpression,
isPropertyAccessOrQualifiedName,
@ -7610,6 +7611,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected) && context.tracker.reportPrivateInBaseOfClassExpression) {
context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName));
}
if (isPrivateIdentifierSymbol(propertySymbol) && context.tracker.reportPrivateInBaseOfClassExpression) {
context.tracker.reportPrivateInBaseOfClassExpression(idText((propertySymbol.valueDeclaration! as NamedDeclaration).name! as PrivateIdentifier));
}
}
if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) {
context.out.truncated = true;

View File

@ -0,0 +1,31 @@
privateFieldsInClassExpressionDeclaration.ts(1,14): error TS4094: Property '#context' of exported anonymous class type may not be private or protected.
privateFieldsInClassExpressionDeclaration.ts(1,14): error TS4094: Property '#method' of exported anonymous class type may not be private or protected.
privateFieldsInClassExpressionDeclaration.ts(8,14): error TS4094: Property '#instancePrivate' of exported anonymous class type may not be private or protected.
privateFieldsInClassExpressionDeclaration.ts(8,14): error TS4094: Property '#staticPrivate' of exported anonymous class type may not be private or protected.
==== privateFieldsInClassExpressionDeclaration.ts (4 errors) ====
export const ClassExpression = class {
~~~~~~~~~~~~~~~
!!! error TS4094: Property '#context' of exported anonymous class type may not be private or protected.
!!! related TS9027 privateFieldsInClassExpressionDeclaration.ts:1:14: Add a type annotation to the variable ClassExpression.
~~~~~~~~~~~~~~~
!!! error TS4094: Property '#method' of exported anonymous class type may not be private or protected.
!!! related TS9027 privateFieldsInClassExpressionDeclaration.ts:1:14: Add a type annotation to the variable ClassExpression.
#context = 0;
#method() { return 42; }
public value = 1;
};
// Additional test with static private fields
export const ClassExpressionStatic = class {
~~~~~~~~~~~~~~~~~~~~~
!!! error TS4094: Property '#instancePrivate' of exported anonymous class type may not be private or protected.
!!! related TS9027 privateFieldsInClassExpressionDeclaration.ts:8:14: Add a type annotation to the variable ClassExpressionStatic.
~~~~~~~~~~~~~~~~~~~~~
!!! error TS4094: Property '#staticPrivate' of exported anonymous class type may not be private or protected.
!!! related TS9027 privateFieldsInClassExpressionDeclaration.ts:8:14: Add a type annotation to the variable ClassExpressionStatic.
static #staticPrivate = "hidden";
#instancePrivate = true;
public exposed = "visible";
};

View File

@ -0,0 +1,44 @@
//// [tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts] ////
//// [privateFieldsInClassExpressionDeclaration.ts]
export const ClassExpression = class {
#context = 0;
#method() { return 42; }
public value = 1;
};
// Additional test with static private fields
export const ClassExpressionStatic = class {
static #staticPrivate = "hidden";
#instancePrivate = true;
public exposed = "visible";
};
//// [privateFieldsInClassExpressionDeclaration.js]
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 _instances, _context, _method, _a, _b, _ClassExpressionStatic_staticPrivate, _ClassExpressionStatic_instancePrivate;
export const ClassExpression = (_a = class {
constructor() {
_instances.add(this);
_context.set(this, 0);
this.value = 1;
}
},
_context = new WeakMap(),
_instances = new WeakSet(),
_method = function _method() { return 42; },
_a);
// Additional test with static private fields
export const ClassExpressionStatic = (_b = class {
constructor() {
_ClassExpressionStatic_instancePrivate.set(this, true);
this.exposed = "visible";
}
},
_ClassExpressionStatic_instancePrivate = new WeakMap(),
__setFunctionName(_b, "ClassExpressionStatic"),
_ClassExpressionStatic_staticPrivate = { value: "hidden" },
_b);

View File

@ -0,0 +1,31 @@
//// [tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts] ////
=== privateFieldsInClassExpressionDeclaration.ts ===
export const ClassExpression = class {
>ClassExpression : Symbol(ClassExpression, Decl(privateFieldsInClassExpressionDeclaration.ts, 0, 12))
#context = 0;
>#context : Symbol(ClassExpression.#context, Decl(privateFieldsInClassExpressionDeclaration.ts, 0, 38))
#method() { return 42; }
>#method : Symbol(ClassExpression.#method, Decl(privateFieldsInClassExpressionDeclaration.ts, 1, 17))
public value = 1;
>value : Symbol(ClassExpression.value, Decl(privateFieldsInClassExpressionDeclaration.ts, 2, 28))
};
// Additional test with static private fields
export const ClassExpressionStatic = class {
>ClassExpressionStatic : Symbol(ClassExpressionStatic, Decl(privateFieldsInClassExpressionDeclaration.ts, 7, 12))
static #staticPrivate = "hidden";
>#staticPrivate : Symbol(ClassExpressionStatic.#staticPrivate, Decl(privateFieldsInClassExpressionDeclaration.ts, 7, 44))
#instancePrivate = true;
>#instancePrivate : Symbol(ClassExpressionStatic.#instancePrivate, Decl(privateFieldsInClassExpressionDeclaration.ts, 8, 37))
public exposed = "visible";
>exposed : Symbol(ClassExpressionStatic.exposed, Decl(privateFieldsInClassExpressionDeclaration.ts, 9, 28))
};

View File

@ -0,0 +1,55 @@
//// [tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts] ////
=== privateFieldsInClassExpressionDeclaration.ts ===
export const ClassExpression = class {
>ClassExpression : typeof ClassExpression
> : ^^^^^^^^^^^^^^^^^^^^^^
>class { #context = 0; #method() { return 42; } public value = 1;} : typeof ClassExpression
> : ^^^^^^^^^^^^^^^^^^^^^^
#context = 0;
>#context : number
> : ^^^^^^
>0 : 0
> : ^
#method() { return 42; }
>#method : () => number
> : ^^^^^^^^^^^^
>42 : 42
> : ^^
public value = 1;
>value : number
> : ^^^^^^
>1 : 1
> : ^
};
// Additional test with static private fields
export const ClassExpressionStatic = class {
>ClassExpressionStatic : typeof ClassExpressionStatic
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>class { static #staticPrivate = "hidden"; #instancePrivate = true; public exposed = "visible";} : typeof ClassExpressionStatic
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
static #staticPrivate = "hidden";
>#staticPrivate : string
> : ^^^^^^
>"hidden" : "hidden"
> : ^^^^^^^^
#instancePrivate = true;
>#instancePrivate : boolean
> : ^^^^^^^
>true : true
> : ^^^^
public exposed = "visible";
>exposed : string
> : ^^^^^^
>"visible" : "visible"
> : ^^^^^^^^^
};

View File

@ -0,0 +1,15 @@
// @target: ES2015
// @declaration: true
export const ClassExpression = class {
#context = 0;
#method() { return 42; }
public value = 1;
};
// Additional test with static private fields
export const ClassExpressionStatic = class {
static #staticPrivate = "hidden";
#instancePrivate = true;
public exposed = "visible";
};