Skip to content

Commit 39c5d01

Browse files
CopilotRyanCavanaughweswighamtypescript-bot
authored
Fix private identifier fields generating errors in class expression declarations (#62155)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: RyanCavanaugh <[email protected]> Co-authored-by: weswigham <[email protected]> Co-authored-by: Wesley Wigham <[email protected]> Co-authored-by: TypeScript Bot <[email protected]>
1 parent c3ee238 commit 39c5d01

6 files changed

+180
-0
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ import {
710710
isPrivateIdentifier,
711711
isPrivateIdentifierClassElementDeclaration,
712712
isPrivateIdentifierPropertyAccessExpression,
713+
isPrivateIdentifierSymbol,
713714
isPropertyAccessEntityNameExpression,
714715
isPropertyAccessExpression,
715716
isPropertyAccessOrQualifiedName,
@@ -7610,6 +7611,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
76107611
if (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected) && context.tracker.reportPrivateInBaseOfClassExpression) {
76117612
context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName));
76127613
}
7614+
if (isPrivateIdentifierSymbol(propertySymbol) && context.tracker.reportPrivateInBaseOfClassExpression) {
7615+
context.tracker.reportPrivateInBaseOfClassExpression(idText((propertySymbol.valueDeclaration! as NamedDeclaration).name! as PrivateIdentifier));
7616+
}
76137617
}
76147618
if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) {
76157619
context.out.truncated = true;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
privateFieldsInClassExpressionDeclaration.ts(1,14): error TS4094: Property '#context' of exported anonymous class type may not be private or protected.
2+
privateFieldsInClassExpressionDeclaration.ts(1,14): error TS4094: Property '#method' of exported anonymous class type may not be private or protected.
3+
privateFieldsInClassExpressionDeclaration.ts(8,14): error TS4094: Property '#instancePrivate' of exported anonymous class type may not be private or protected.
4+
privateFieldsInClassExpressionDeclaration.ts(8,14): error TS4094: Property '#staticPrivate' of exported anonymous class type may not be private or protected.
5+
6+
7+
==== privateFieldsInClassExpressionDeclaration.ts (4 errors) ====
8+
export const ClassExpression = class {
9+
~~~~~~~~~~~~~~~
10+
!!! error TS4094: Property '#context' of exported anonymous class type may not be private or protected.
11+
!!! related TS9027 privateFieldsInClassExpressionDeclaration.ts:1:14: Add a type annotation to the variable ClassExpression.
12+
~~~~~~~~~~~~~~~
13+
!!! error TS4094: Property '#method' of exported anonymous class type may not be private or protected.
14+
!!! related TS9027 privateFieldsInClassExpressionDeclaration.ts:1:14: Add a type annotation to the variable ClassExpression.
15+
#context = 0;
16+
#method() { return 42; }
17+
public value = 1;
18+
};
19+
20+
// Additional test with static private fields
21+
export const ClassExpressionStatic = class {
22+
~~~~~~~~~~~~~~~~~~~~~
23+
!!! error TS4094: Property '#instancePrivate' of exported anonymous class type may not be private or protected.
24+
!!! related TS9027 privateFieldsInClassExpressionDeclaration.ts:8:14: Add a type annotation to the variable ClassExpressionStatic.
25+
~~~~~~~~~~~~~~~~~~~~~
26+
!!! error TS4094: Property '#staticPrivate' of exported anonymous class type may not be private or protected.
27+
!!! related TS9027 privateFieldsInClassExpressionDeclaration.ts:8:14: Add a type annotation to the variable ClassExpressionStatic.
28+
static #staticPrivate = "hidden";
29+
#instancePrivate = true;
30+
public exposed = "visible";
31+
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//// [tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts] ////
2+
3+
//// [privateFieldsInClassExpressionDeclaration.ts]
4+
export const ClassExpression = class {
5+
#context = 0;
6+
#method() { return 42; }
7+
public value = 1;
8+
};
9+
10+
// Additional test with static private fields
11+
export const ClassExpressionStatic = class {
12+
static #staticPrivate = "hidden";
13+
#instancePrivate = true;
14+
public exposed = "visible";
15+
};
16+
17+
//// [privateFieldsInClassExpressionDeclaration.js]
18+
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
19+
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
20+
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
21+
};
22+
var _instances, _context, _method, _a, _b, _ClassExpressionStatic_staticPrivate, _ClassExpressionStatic_instancePrivate;
23+
export const ClassExpression = (_a = class {
24+
constructor() {
25+
_instances.add(this);
26+
_context.set(this, 0);
27+
this.value = 1;
28+
}
29+
},
30+
_context = new WeakMap(),
31+
_instances = new WeakSet(),
32+
_method = function _method() { return 42; },
33+
_a);
34+
// Additional test with static private fields
35+
export const ClassExpressionStatic = (_b = class {
36+
constructor() {
37+
_ClassExpressionStatic_instancePrivate.set(this, true);
38+
this.exposed = "visible";
39+
}
40+
},
41+
_ClassExpressionStatic_instancePrivate = new WeakMap(),
42+
__setFunctionName(_b, "ClassExpressionStatic"),
43+
_ClassExpressionStatic_staticPrivate = { value: "hidden" },
44+
_b);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts] ////
2+
3+
=== privateFieldsInClassExpressionDeclaration.ts ===
4+
export const ClassExpression = class {
5+
>ClassExpression : Symbol(ClassExpression, Decl(privateFieldsInClassExpressionDeclaration.ts, 0, 12))
6+
7+
#context = 0;
8+
>#context : Symbol(ClassExpression.#context, Decl(privateFieldsInClassExpressionDeclaration.ts, 0, 38))
9+
10+
#method() { return 42; }
11+
>#method : Symbol(ClassExpression.#method, Decl(privateFieldsInClassExpressionDeclaration.ts, 1, 17))
12+
13+
public value = 1;
14+
>value : Symbol(ClassExpression.value, Decl(privateFieldsInClassExpressionDeclaration.ts, 2, 28))
15+
16+
};
17+
18+
// Additional test with static private fields
19+
export const ClassExpressionStatic = class {
20+
>ClassExpressionStatic : Symbol(ClassExpressionStatic, Decl(privateFieldsInClassExpressionDeclaration.ts, 7, 12))
21+
22+
static #staticPrivate = "hidden";
23+
>#staticPrivate : Symbol(ClassExpressionStatic.#staticPrivate, Decl(privateFieldsInClassExpressionDeclaration.ts, 7, 44))
24+
25+
#instancePrivate = true;
26+
>#instancePrivate : Symbol(ClassExpressionStatic.#instancePrivate, Decl(privateFieldsInClassExpressionDeclaration.ts, 8, 37))
27+
28+
public exposed = "visible";
29+
>exposed : Symbol(ClassExpressionStatic.exposed, Decl(privateFieldsInClassExpressionDeclaration.ts, 9, 28))
30+
31+
};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//// [tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts] ////
2+
3+
=== privateFieldsInClassExpressionDeclaration.ts ===
4+
export const ClassExpression = class {
5+
>ClassExpression : typeof ClassExpression
6+
> : ^^^^^^^^^^^^^^^^^^^^^^
7+
>class { #context = 0; #method() { return 42; } public value = 1;} : typeof ClassExpression
8+
> : ^^^^^^^^^^^^^^^^^^^^^^
9+
10+
#context = 0;
11+
>#context : number
12+
> : ^^^^^^
13+
>0 : 0
14+
> : ^
15+
16+
#method() { return 42; }
17+
>#method : () => number
18+
> : ^^^^^^^^^^^^
19+
>42 : 42
20+
> : ^^
21+
22+
public value = 1;
23+
>value : number
24+
> : ^^^^^^
25+
>1 : 1
26+
> : ^
27+
28+
};
29+
30+
// Additional test with static private fields
31+
export const ClassExpressionStatic = class {
32+
>ClassExpressionStatic : typeof ClassExpressionStatic
33+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
>class { static #staticPrivate = "hidden"; #instancePrivate = true; public exposed = "visible";} : typeof ClassExpressionStatic
35+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36+
37+
static #staticPrivate = "hidden";
38+
>#staticPrivate : string
39+
> : ^^^^^^
40+
>"hidden" : "hidden"
41+
> : ^^^^^^^^
42+
43+
#instancePrivate = true;
44+
>#instancePrivate : boolean
45+
> : ^^^^^^^
46+
>true : true
47+
> : ^^^^
48+
49+
public exposed = "visible";
50+
>exposed : string
51+
> : ^^^^^^
52+
>"visible" : "visible"
53+
> : ^^^^^^^^^
54+
55+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @target: ES2015
2+
// @declaration: true
3+
4+
export const ClassExpression = class {
5+
#context = 0;
6+
#method() { return 42; }
7+
public value = 1;
8+
};
9+
10+
// Additional test with static private fields
11+
export const ClassExpressionStatic = class {
12+
static #staticPrivate = "hidden";
13+
#instancePrivate = true;
14+
public exposed = "visible";
15+
};

0 commit comments

Comments
 (0)