diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 77f35376da785..aac52abfc4dd4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8908,7 +8908,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getPropertyNameNodeForSymbol(symbol: Symbol, context: NodeBuilderContext) { const hashPrivateName = getClonedHashPrivateName(symbol); if (hashPrivateName) { - return hashPrivateName; + const shouldEmitErroneousFieldName = !!context.tracker.reportPrivateInBaseOfClassExpression && + context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral; + if (!shouldEmitErroneousFieldName) { + return hashPrivateName; + } + else { + let rawName = unescapeLeadingUnderscores(symbol.escapedName); + // symbol IDs are unstable - replace #nnn# with #private# + rawName = rawName.replace(/__#\d+@#/g, "__#private@#"); + return createPropertyNameNodeForIdentifierOrLiteral(rawName, getEmitScriptTarget(compilerOptions), /*singleQuote*/ false, /*stringNamed*/ true, !!(symbol.flags & SymbolFlags.Method)); + } } const stringNamed = !!length(symbol.declarations) && every(symbol.declarations, isStringNamed); const singleQuote = !!length(symbol.declarations) && every(symbol.declarations, isSingleQuotedStringNamed); diff --git a/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.js b/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.js new file mode 100644 index 0000000000000..d6156b1c31fc3 --- /dev/null +++ b/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.js @@ -0,0 +1,61 @@ +//// [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); + + +//// [privateFieldsInClassExpressionDeclaration.d.ts] +export declare const ClassExpression: { + new (): { + "__#private@#context": number; + "__#private@#method"(): number; + value: number; + }; +}; +export declare const ClassExpressionStatic: { + new (): { + "__#private@#instancePrivate": boolean; + exposed: string; + }; + "__#private@#staticPrivate": string; +}; diff --git a/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.symbols b/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.symbols new file mode 100644 index 0000000000000..395e587de77bd --- /dev/null +++ b/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.symbols @@ -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)) + +}; diff --git a/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.types b/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.types new file mode 100644 index 0000000000000..2377b1ba09167 --- /dev/null +++ b/tests/baselines/reference/privateFieldsInClassExpressionDeclaration.types @@ -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" +> : ^^^^^^^^^ + +}; diff --git a/tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts b/tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts new file mode 100644 index 0000000000000..f6fcfdda17091 --- /dev/null +++ b/tests/cases/compiler/privateFieldsInClassExpressionDeclaration.ts @@ -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"; +}; \ No newline at end of file