diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 5bd544035f09e..ea44028dc5727 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -225,10 +225,6 @@ namespace ts { node.symbol = symbol; symbol.declarations = append(symbol.declarations, node); - if (isNamedDeclaration(node) && isPrivateName(node.name)) { - symbol.flags |= SymbolFlags.PrivateNamed; - } - if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) && !symbol.exports) { symbol.exports = createSymbolTable(); } @@ -270,6 +266,11 @@ namespace ts { Debug.assert(isWellKnownSymbolSyntactically(nameExpression)); return getPropertyNameForKnownSymbolName(idText((nameExpression).name)); } + if (isPrivateName(name)) { + // containingClass exists because private names only allowed inside classes + const containingClassSymbol = getContainingClass(name.parent)!.symbol; + return getPropertyNameForPrivateName(containingClassSymbol, name.escapedText); + } return isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; } switch (node.kind) { @@ -326,6 +327,10 @@ namespace ts { const isDefaultExport = hasModifier(node, ModifierFlags.Default); + // need this before getDeclarationName + if (isNamedDeclaration(node)) { + node.name.parent = node; + } // The exported symbol for an export default function/class node is always named "default" const name = isDefaultExport && parent ? InternalSymbolName.Default : getDeclarationName(node); @@ -378,10 +383,6 @@ namespace ts { symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name)); } else { - if (isNamedDeclaration(node)) { - node.name.parent = node; - } - // Report errors every position with duplicate declaration // Report errors on previous encountered declarations let message = symbol.flags & SymbolFlags.BlockScopedVariable diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4c44a9b39ffb9..662fec7a5897b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2594,15 +2594,16 @@ namespace ts { return getUnionType(arrayFrom(typeofEQFacts.keys(), getLiteralType)); } - // A reserved member name starts with two underscores, but the third character cannot be an underscore - // or the @ symbol. A third underscore indicates an escaped form of an identifer that started + // A reserved member name starts with two underscores, but the third character cannot be an underscore, + // @ or #. A third underscore indicates an escaped form of an identifer that started // with at least two underscores. The @ character indicates that the name is denoted by a well known ES - // Symbol instance. + // Symbol instance and the # indicates that the name is a PrivateName. function isReservedMemberName(name: __String) { return (name as string).charCodeAt(0) === CharacterCodes._ && (name as string).charCodeAt(1) === CharacterCodes._ && (name as string).charCodeAt(2) !== CharacterCodes._ && - (name as string).charCodeAt(2) !== CharacterCodes.at; + (name as string).charCodeAt(2) !== CharacterCodes.at && + (name as string).charCodeAt(2) !== CharacterCodes.hash; } function getNamedMembers(members: SymbolTable): Symbol[] { @@ -7276,11 +7277,12 @@ namespace ts { * @param type a type to look up property from * @param name a name of property to look up in a given type */ - function getPropertyOfType(type: Type, name: __String): Symbol | undefined { + function getPropertyOfType(type: Type, name: __String, isPrivateName = false): Symbol | undefined { type = getApparentType(type); if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type); - const symbol = resolved.members.get(name); + const symbolTableKey = isPrivateName ? getPropertyNameForPrivateName(type.symbol, name) : name; + const symbol = resolved.members.get(symbolTableKey); if (symbol && symbolIsValue(symbol)) { return symbol; } @@ -9042,7 +9044,9 @@ namespace ts { } function getLiteralTypeFromPropertyName(prop: Symbol, include: TypeFlags) { - if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) { + const hasNonPublicModifier = !!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier); + const hasPrivateName = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) && isPrivateName(prop.valueDeclaration.name); + if (!hasNonPublicModifier && !hasPrivateName) { let type = getLateBoundSymbol(prop).nameType; if (!type && !isKnownSymbol(prop)) { const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration); @@ -13187,9 +13191,6 @@ namespace ts { const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(target) : getPropertiesOfObjectType(target); for (const targetProp of properties) { if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) { - if (targetProp.flags & SymbolFlags.PrivateNamed) { - return targetProp; - } const sourceProp = getPropertyOfType(source, targetProp.escapedName); if (!sourceProp) { return targetProp; @@ -17866,7 +17867,7 @@ namespace ts { if (node.kind === SyntaxKind.PropertyAccessExpression && isPrivateName(node.name)) { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!)!; if (!isNodeWithinClass(node, declaringClassDeclaration)) { - error(errorNode, Diagnostics.Property_0_is_only_accessible_within_class_1_because_it_has_a_private_name, symbolToString(prop), typeToString(getDeclaringClass(prop)!)); + error(errorNode, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_name, symbolToString(prop), typeToString(getDeclaringClass(prop)!)); return false; } return true; @@ -17999,13 +18000,13 @@ namespace ts { return apparentType; } const assignmentKind = getAssignmentTargetKind(node); - const prop = getPropertyOfType(apparentType, right.escapedText); + const prop = getPropertyOfType(apparentType, right.escapedText, isPrivateName(right)); if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) { markAliasReferenced(parentSymbol, node); } if (!prop) { const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String); - if (!(indexInfo && indexInfo.type) || isPrivateName(right)) { + if (!(indexInfo && indexInfo.type)) { if (isJSLiteralType(leftType)) { return anyType; } @@ -25442,10 +25443,6 @@ namespace ts { const declaredProp = member.name && getSymbolAtLocation(member.name) || getSymbolAtLocation(member); if (declaredProp) { const prop = getPropertyOfType(typeWithThis, declaredProp.escapedName); - // skip inheritance checks because private names are unique to each class - if (member.name && isPrivateName(member.name)) { - return; - } const baseProp = getPropertyOfType(baseWithThis, declaredProp.escapedName); if (prop && baseProp) { const rootChain = () => chainDiagnosticMessages( diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index aeba5834bd8c8..8fcc1764a470c 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4178,7 +4178,7 @@ "category": "Error", "code": 18006 }, - "Property '{0}' is only accessible within class '{1}' because it has a private name.": { + "Property '{0}' is not accessible outside class '{1}' because it has a private name.": { "category": "Error", "code": 18007 }, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b2ad0db07aa3f..4b2357bc63e77 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3433,7 +3433,6 @@ namespace ts { Transient = 1 << 25, // Transient symbol (created during type check) JSContainer = 1 << 26, // Contains Javascript special declarations ModuleExports = 1 << 27, // Symbol for CommonJS `module` of `module.exports` - PrivateNamed = 1 << 28, // Symbol's name is a private name (example: `#foo`) /* @internal */ All = FunctionScopedVariable | BlockScopedVariable | Property | EnumMember | Function | Class | Interface | ConstEnum | RegularEnum | ValueModule | NamespaceModule | TypeLiteral diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b8e12539e07da..7428da86450fe 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2672,6 +2672,10 @@ namespace ts { return "__@" + symbolName as __String; } + export function getPropertyNameForPrivateName(containingClassSymbol: Symbol, escapedText: __String): __String { + return `__#${getSymbolId(containingClassSymbol)}@${escapedText}` as __String; + } + export function isKnownSymbol(symbol: Symbol): boolean { return startsWith(symbol.escapedName as string, "__@"); } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index fcc8434c0d3c0..1ab1a986d1ad1 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2063,7 +2063,6 @@ declare namespace ts { Transient = 33554432, JSContainer = 67108864, ModuleExports = 134217728, - PrivateNamed = 268435456, Enum = 384, Variable = 3, Value = 67216319, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 03867ae19cb45..ea78225538eac 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2063,7 +2063,6 @@ declare namespace ts { Transient = 33554432, JSContainer = 67108864, ModuleExports = 134217728, - PrivateNamed = 268435456, Enum = 384, Variable = 3, Value = 67216319, diff --git a/tests/baselines/reference/privateNameAndIndexSignature.errors.txt b/tests/baselines/reference/privateNameAndIndexSignature.errors.txt deleted file mode 100644 index 1b4895bf23d64..0000000000000 --- a/tests/baselines/reference/privateNameAndIndexSignature.errors.txt +++ /dev/null @@ -1,13 +0,0 @@ -tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts(4,14): error TS2339: Property '#f' does not exist on type 'A'. - - -==== tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts (1 errors) ==== - class A { - [k: string]: any; - constructor(message: string) { - this.#f = 3 // Error Property '#f' does not exist on type 'A'. - ~~ -!!! error TS2339: Property '#f' does not exist on type 'A'. - } - } - \ No newline at end of file diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt index 61b892d67ddc4..904f4729d5ac0 100644 --- a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts(5,9): error TS18007: Property '#foo' is only accessible within class 'A' because it has a private name. +tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts(5,9): error TS18007: Property '#foo' is not accessible outside class 'A' because it has a private name. ==== tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts (1 errors) ==== @@ -8,5 +8,5 @@ tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOut new A().#foo = 4; // Error ~~~~ -!!! error TS18007: Property '#foo' is only accessible within class 'A' because it has a private name. +!!! error TS18007: Property '#foo' is not accessible outside class 'A' because it has a private name. \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesAndkeyof.js b/tests/baselines/reference/privateNamesAndkeyof.js new file mode 100644 index 0000000000000..90d72a3b62944 --- /dev/null +++ b/tests/baselines/reference/privateNamesAndkeyof.js @@ -0,0 +1,16 @@ +//// [privateNamesAndkeyof.ts] +class A { + #foo; + bar; + baz; +} + +type T = keyof A // should not include '#foo' + + +//// [privateNamesAndkeyof.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); diff --git a/tests/baselines/reference/privateNamesAndkeyof.symbols b/tests/baselines/reference/privateNamesAndkeyof.symbols new file mode 100644 index 0000000000000..67a7d46b52dd7 --- /dev/null +++ b/tests/baselines/reference/privateNamesAndkeyof.symbols @@ -0,0 +1,18 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts === +class A { +>A : Symbol(A, Decl(privateNamesAndkeyof.ts, 0, 0)) + + #foo; +>#foo : Symbol(A[#foo], Decl(privateNamesAndkeyof.ts, 0, 9)) + + bar; +>bar : Symbol(A.bar, Decl(privateNamesAndkeyof.ts, 1, 9)) + + baz; +>baz : Symbol(A.baz, Decl(privateNamesAndkeyof.ts, 2, 8)) +} + +type T = keyof A // should not include '#foo' +>T : Symbol(T, Decl(privateNamesAndkeyof.ts, 4, 1)) +>A : Symbol(A, Decl(privateNamesAndkeyof.ts, 0, 0)) + diff --git a/tests/baselines/reference/privateNamesAndkeyof.types b/tests/baselines/reference/privateNamesAndkeyof.types new file mode 100644 index 0000000000000..a43c7dcd6c534 --- /dev/null +++ b/tests/baselines/reference/privateNamesAndkeyof.types @@ -0,0 +1,17 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts === +class A { +>A : A + + #foo; +>#foo : any + + bar; +>bar : any + + baz; +>baz : any +} + +type T = keyof A // should not include '#foo' +>T : "bar" | "baz" + diff --git a/tests/baselines/reference/privateNamesInGenericClasses.errors.txt b/tests/baselines/reference/privateNamesInGenericClasses.errors.txt new file mode 100644 index 0000000000000..9da803c3ca597 --- /dev/null +++ b/tests/baselines/reference/privateNamesInGenericClasses.errors.txt @@ -0,0 +1,29 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts(10,3): error TS18007: Property '#foo' is not accessible outside class 'C' because it has a private name. +tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts(11,1): error TS2322: Type 'C' is not assignable to type 'C'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts(12,1): error TS2322: Type 'C' is not assignable to type 'C'. + Type 'number' is not assignable to type 'string'. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts (3 errors) ==== + class C { + #foo: T; + bar(x: C) { return x.#foo; } // OK + baz(x: C) { return x.#foo; } // OK + quux(x: C) { return x.#foo; } // OK + } + + declare let a: C; + declare let b: C; + a.#foo; // OK + ~~~~ +!!! error TS18007: Property '#foo' is not accessible outside class 'C' because it has a private name. + a = b; // Error + ~ +!!! error TS2322: Type 'C' is not assignable to type 'C'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + b = a; // Error + ~ +!!! error TS2322: Type 'C' is not assignable to type 'C'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesInGenericClasses.js b/tests/baselines/reference/privateNamesInGenericClasses.js new file mode 100644 index 0000000000000..dcee4e0fd82ef --- /dev/null +++ b/tests/baselines/reference/privateNamesInGenericClasses.js @@ -0,0 +1,27 @@ +//// [privateNamesInGenericClasses.ts] +class C { + #foo: T; + bar(x: C) { return x.#foo; } // OK + baz(x: C) { return x.#foo; } // OK + quux(x: C) { return x.#foo; } // OK +} + +declare let a: C; +declare let b: C; +a.#foo; // OK +a = b; // Error +b = a; // Error + + +//// [privateNamesInGenericClasses.js] +var C = /** @class */ (function () { + function C() { + } + C.prototype.bar = function (x) { return x.#foo; }; // OK + C.prototype.baz = function (x) { return x.#foo; }; // OK + C.prototype.quux = function (x) { return x.#foo; }; // OK + return C; +}()); +a.#foo; // OK +a = b; // Error +b = a; // Error diff --git a/tests/baselines/reference/privateNamesInGenericClasses.symbols b/tests/baselines/reference/privateNamesInGenericClasses.symbols new file mode 100644 index 0000000000000..a07fa125d37dd --- /dev/null +++ b/tests/baselines/reference/privateNamesInGenericClasses.symbols @@ -0,0 +1,52 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts === +class C { +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) +>T : Symbol(T, Decl(privateNamesInGenericClasses.ts, 0, 8)) + + #foo: T; +>#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>T : Symbol(T, Decl(privateNamesInGenericClasses.ts, 0, 8)) + + bar(x: C) { return x.#foo; } // OK +>bar : Symbol(C.bar, Decl(privateNamesInGenericClasses.ts, 1, 10)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 2, 6)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) +>T : Symbol(T, Decl(privateNamesInGenericClasses.ts, 0, 8)) +>x.#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 2, 6)) + + baz(x: C) { return x.#foo; } // OK +>baz : Symbol(C.baz, Decl(privateNamesInGenericClasses.ts, 2, 33)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 3, 6)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) +>x.#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 3, 6)) + + quux(x: C) { return x.#foo; } // OK +>quux : Symbol(C.quux, Decl(privateNamesInGenericClasses.ts, 3, 38)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 4, 7)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) +>x.#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>x : Symbol(x, Decl(privateNamesInGenericClasses.ts, 4, 7)) +} + +declare let a: C; +>a : Symbol(a, Decl(privateNamesInGenericClasses.ts, 7, 11)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) + +declare let b: C; +>b : Symbol(b, Decl(privateNamesInGenericClasses.ts, 8, 11)) +>C : Symbol(C, Decl(privateNamesInGenericClasses.ts, 0, 0)) + +a.#foo; // OK +>a.#foo : Symbol(C[#foo], Decl(privateNamesInGenericClasses.ts, 0, 12)) +>a : Symbol(a, Decl(privateNamesInGenericClasses.ts, 7, 11)) + +a = b; // Error +>a : Symbol(a, Decl(privateNamesInGenericClasses.ts, 7, 11)) +>b : Symbol(b, Decl(privateNamesInGenericClasses.ts, 8, 11)) + +b = a; // Error +>b : Symbol(b, Decl(privateNamesInGenericClasses.ts, 8, 11)) +>a : Symbol(a, Decl(privateNamesInGenericClasses.ts, 7, 11)) + diff --git a/tests/baselines/reference/privateNamesInGenericClasses.types b/tests/baselines/reference/privateNamesInGenericClasses.types new file mode 100644 index 0000000000000..41f33670836c3 --- /dev/null +++ b/tests/baselines/reference/privateNamesInGenericClasses.types @@ -0,0 +1,46 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts === +class C { +>C : C + + #foo: T; +>#foo : T + + bar(x: C) { return x.#foo; } // OK +>bar : (x: C) => T +>x : C +>x.#foo : T +>x : C + + baz(x: C) { return x.#foo; } // OK +>baz : (x: C) => number +>x : C +>x.#foo : number +>x : C + + quux(x: C) { return x.#foo; } // OK +>quux : (x: C) => string +>x : C +>x.#foo : string +>x : C +} + +declare let a: C; +>a : C + +declare let b: C; +>b : C + +a.#foo; // OK +>a.#foo : number +>a : C + +a = b; // Error +>a = b : C +>a : C +>b : C + +b = a; // Error +>b = a : C +>b : C +>a : C + diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js index 0dbc7ec223be7..7d17373ace173 100644 --- a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js @@ -4,8 +4,10 @@ class A { } class B extends A { - #foo: string; // OK: private names are unique to each class + #foo: string; // OK: private names are unique to each class } + +const b: A = new B() // OK //// [privateNamesNoConflictWhenInheriting.js] @@ -34,3 +36,4 @@ var B = /** @class */ (function (_super) { } return B; }(A)); +var b = new B(); // OK diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols index 7ce208e54b3c0..11ee25651c95f 100644 --- a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols @@ -10,7 +10,12 @@ class B extends A { >B : Symbol(B, Decl(privateNamesNoConflictWhenInheriting.ts, 2, 1)) >A : Symbol(A, Decl(privateNamesNoConflictWhenInheriting.ts, 0, 0)) - #foo: string; // OK: private names are unique to each class + #foo: string; // OK: private names are unique to each class >#foo : Symbol(B[#foo], Decl(privateNamesNoConflictWhenInheriting.ts, 4, 19)) } +const b: A = new B() // OK +>b : Symbol(b, Decl(privateNamesNoConflictWhenInheriting.ts, 8, 5)) +>A : Symbol(A, Decl(privateNamesNoConflictWhenInheriting.ts, 0, 0)) +>B : Symbol(B, Decl(privateNamesNoConflictWhenInheriting.ts, 2, 1)) + diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types index 3b7213ae2a97e..40459f74d2e63 100644 --- a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types @@ -10,7 +10,12 @@ class B extends A { >B : B >A : A - #foo: string; // OK: private names are unique to each class + #foo: string; // OK: private names are unique to each class >#foo : string } +const b: A = new B() // OK +>b : A +>new B() : B +>B : typeof B + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts new file mode 100644 index 0000000000000..93edade95ce9e --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesAndkeyof.ts @@ -0,0 +1,7 @@ +class A { + #foo; + bar; + baz; +} + +type T = keyof A // should not include '#foo' diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts new file mode 100644 index 0000000000000..c1369caf48594 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesInGenericClasses.ts @@ -0,0 +1,12 @@ +class C { + #foo: T; + bar(x: C) { return x.#foo; } // OK + baz(x: C) { return x.#foo; } // OK + quux(x: C) { return x.#foo; } // OK +} + +declare let a: C; +declare let b: C; +a.#foo; // OK +a = b; // Error +b = a; // Error diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts index dae3d40cea03c..bb55edd9b3dfc 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts @@ -3,5 +3,7 @@ class A { } class B extends A { - #foo: string; // OK: private names are unique to each class + #foo: string; // OK: private names are unique to each class } + +const b: A = new B() // OK