diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index ebc43e006bdfc..5bd544035f09e 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -225,6 +225,10 @@ 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(); } @@ -266,9 +270,6 @@ namespace ts { Debug.assert(isWellKnownSymbolSyntactically(nameExpression)); return getPropertyNameForKnownSymbolName(idText((nameExpression).name)); } - if (isPrivateName(node)) { - return nodePosToString(node) as __String; - } return isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; } switch (node.kind) { @@ -1798,6 +1799,18 @@ namespace ts { return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode; } + // The binder visits every node, so this is a good place to check for + // the reserved private name (there is only one) + function checkPrivateName(node: PrivateName) { + if (node.escapedText === "#constructor") { + // Report error only if there are no parse errors in file + if (!file.parseDiagnostics.length) { + file.bindDiagnostics.push(createDiagnosticForNode(node, + Diagnostics.constructor_is_a_reserved_word, declarationNameToString(node))); + } + } + } + function checkStrictModeBinaryExpression(node: BinaryExpression) { if (inStrictMode && isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) { // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an @@ -2070,6 +2083,8 @@ namespace ts { node.flowNode = currentFlow; } return checkStrictModeIdentifier(node); + case SyntaxKind.PrivateName: + return checkPrivateName(node as PrivateName); case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: if (currentFlow && isNarrowableReference(node)) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bb68b71a02e2d..4c44a9b39ffb9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13187,6 +13187,9 @@ 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; @@ -17860,6 +17863,16 @@ 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)!)); + return false; + } + return true; + } + + // Public properties are otherwise accessible. if (!(flags & ModifierFlags.NonPublicAccessibilityModifier)) { return true; @@ -20725,10 +20738,16 @@ namespace ts { error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference); return booleanType; } + if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) { + error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name); + + } const links = getNodeLinks(expr); const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol); - if (symbol && isReadonlySymbol(symbol)) { - error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property); + if (symbol) { + if (isReadonlySymbol(symbol)) { + error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property); + } } return booleanType; } @@ -21878,9 +21897,6 @@ namespace ts { checkGrammarDecoratorsAndModifiers(node); checkVariableLikeDeclaration(node); - if (node.name && isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) { - error(node, Diagnostics.Private_names_cannot_be_used_as_parameters); - } const func = getContainingFunction(node)!; if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) { if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { @@ -25426,6 +25442,10 @@ 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( @@ -28515,6 +28535,9 @@ namespace ts { else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (node).dotDotDotToken) { return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter); } + else if (isNamedDeclaration(node) && (flags & ModifierFlags.AccessibilityModifier) && node.name.kind === SyntaxKind.PrivateName) { + return grammarErrorOnNode(node, Diagnostics.Accessibility_modifiers_cannot_be_used_with_private_names); + } if (flags & ModifierFlags.Async) { return checkGrammarAsyncModifier(node, lastAsync!); } @@ -29293,10 +29316,6 @@ namespace ts { checkESModuleMarker(node.name); } - if (isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) { - return grammarErrorOnNode(node.name, Diagnostics.Private_names_are_not_allowed_in_variable_declarations); - } - const checkLetConstNames = (isLet(node) || isVarConst(node)); // 1. LexicalDeclaration : LetOrConst BindingList ; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a1d6859db7154..aeba5834bd8c8 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4166,14 +4166,23 @@ "category": "Error", "code": 18003 }, - "Private names are not allowed in variable declarations.": { + "Accessibility modifiers cannot be used with private names.": { "category": "Error", "code": 18004 }, - "Private names cannot be used as parameters": { + "The operand of a delete operator cannot be a private name.": { "category": "Error", "code": 18005 }, + "#constructor is a reserved word.": { + "category": "Error", + "code": 18006 + }, + "Property '{0}' is only accessible within class '{1}' because it has a private name.": { + "category": "Error", + "code": 18007 + }, + "File is a CommonJS module; it may be converted to an ES6 module.": { "category": "Suggestion", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4b2357bc63e77..b2ad0db07aa3f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3433,6 +3433,7 @@ 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/tests/baselines/reference/privateNameConstructorReserved.errors.txt b/tests/baselines/reference/privateNameConstructorReserved.errors.txt new file mode 100644 index 0000000000000..0e19a569e8fbe --- /dev/null +++ b/tests/baselines/reference/privateNameConstructorReserved.errors.txt @@ -0,0 +1,22 @@ +tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts(1,7): error TS2300: Duplicate identifier 'A'. +tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts(2,5): error TS18006: #constructor is a reserved word. +tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts(5,7): error TS2300: Duplicate identifier 'A'. +tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts(6,5): error TS18006: #constructor is a reserved word. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts (4 errors) ==== + class A { + ~ +!!! error TS2300: Duplicate identifier 'A'. + #constructor() {} // Error: `#constructor` is a reserved word. + ~~~~~~~~~~~~ +!!! error TS18006: #constructor is a reserved word. + } + + class A { + ~ +!!! error TS2300: Duplicate identifier 'A'. + #constructor = 5 // Error: `#constructor` is a reserved word. + ~~~~~~~~~~~~ +!!! error TS18006: #constructor is a reserved word. + } \ No newline at end of file diff --git a/tests/baselines/reference/privateNameConstructorReserved.js b/tests/baselines/reference/privateNameConstructorReserved.js new file mode 100644 index 0000000000000..e393334154560 --- /dev/null +++ b/tests/baselines/reference/privateNameConstructorReserved.js @@ -0,0 +1,22 @@ +//// [privateNameConstructorReserved.ts] +class A { + #constructor() {} // Error: `#constructor` is a reserved word. +} + +class A { + #constructor = 5 // Error: `#constructor` is a reserved word. +} + +//// [privateNameConstructorReserved.js] +var A = /** @class */ (function () { + function A() { + } + A.prototype.#constructor = function () { }; // Error: `#constructor` is a reserved word. + return A; +}()); +var A = /** @class */ (function () { + function A() { + this.#constructor = 5; // Error: `#constructor` is a reserved word. + } + return A; +}()); diff --git a/tests/baselines/reference/privateNameConstructorReserved.symbols b/tests/baselines/reference/privateNameConstructorReserved.symbols new file mode 100644 index 0000000000000..d61e750acb600 --- /dev/null +++ b/tests/baselines/reference/privateNameConstructorReserved.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts === +class A { +>A : Symbol(A, Decl(privateNameConstructorReserved.ts, 0, 0)) + + #constructor() {} // Error: `#constructor` is a reserved word. +>#constructor : Symbol(A[#constructor], Decl(privateNameConstructorReserved.ts, 0, 9)) +} + +class A { +>A : Symbol(A, Decl(privateNameConstructorReserved.ts, 2, 1)) + + #constructor = 5 // Error: `#constructor` is a reserved word. +>#constructor : Symbol(A[#constructor], Decl(privateNameConstructorReserved.ts, 4, 9)) +} diff --git a/tests/baselines/reference/privateNameConstructorReserved.types b/tests/baselines/reference/privateNameConstructorReserved.types new file mode 100644 index 0000000000000..008329efd5e30 --- /dev/null +++ b/tests/baselines/reference/privateNameConstructorReserved.types @@ -0,0 +1,15 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts === +class A { +>A : A + + #constructor() {} // Error: `#constructor` is a reserved word. +>#constructor : () => void +} + +class A { +>A : A + + #constructor = 5 // Error: `#constructor` is a reserved word. +>#constructor : number +>5 : 5 +} diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt new file mode 100644 index 0000000000000..61b892d67ddc4 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.errors.txt @@ -0,0 +1,12 @@ +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 (1 errors) ==== + class A { + #foo: number = 3; + } + + new A().#foo = 4; // Error + ~~~~ +!!! error TS18007: Property '#foo' is only accessible within class 'A' because it has a private name. + \ No newline at end of file diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.js b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.js new file mode 100644 index 0000000000000..c096ffe8efe41 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.js @@ -0,0 +1,16 @@ +//// [privateNameNotAccessibleOutsideDefiningClass.ts] +class A { + #foo: number = 3; +} + +new A().#foo = 4; // Error + + +//// [privateNameNotAccessibleOutsideDefiningClass.js] +var A = /** @class */ (function () { + function A() { + this.#foo = 3; + } + return A; +}()); +new A().#foo = 4; // Error diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.symbols b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.symbols new file mode 100644 index 0000000000000..8c2ae13977053 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.symbols @@ -0,0 +1,12 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts === +class A { +>A : Symbol(A, Decl(privateNameNotAccessibleOutsideDefiningClass.ts, 0, 0)) + + #foo: number = 3; +>#foo : Symbol(A[#foo], Decl(privateNameNotAccessibleOutsideDefiningClass.ts, 0, 9)) +} + +new A().#foo = 4; // Error +>new A().#foo : Symbol(A[#foo], Decl(privateNameNotAccessibleOutsideDefiningClass.ts, 0, 9)) +>A : Symbol(A, Decl(privateNameNotAccessibleOutsideDefiningClass.ts, 0, 0)) + diff --git a/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.types b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.types new file mode 100644 index 0000000000000..5ffbd2187c765 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAccessibleOutsideDefiningClass.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts === +class A { +>A : A + + #foo: number = 3; +>#foo : number +>3 : 3 +} + +new A().#foo = 4; // Error +>new A().#foo = 4 : 4 +>new A().#foo : number +>new A() : A +>A : typeof A +>4 : 4 + diff --git a/tests/baselines/reference/privateNameNotAllowedOutsideClass.errors.txt b/tests/baselines/reference/privateNameNotAllowedOutsideClass.errors.txt new file mode 100644 index 0000000000000..f4b6a6364f6b8 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAllowedOutsideClass.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts(1,7): error TS1134: Variable declaration expected. +tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts(1,12): error TS1134: Variable declaration expected. +tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts(1,14): error TS1134: Variable declaration expected. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts (3 errors) ==== + const #foo = 3; + ~~~~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/privateNameNotAllowedOutsideClass.js b/tests/baselines/reference/privateNameNotAllowedOutsideClass.js new file mode 100644 index 0000000000000..ff289b3d29c54 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAllowedOutsideClass.js @@ -0,0 +1,6 @@ +//// [privateNameNotAllowedOutsideClass.ts] +const #foo = 3; + +//// [privateNameNotAllowedOutsideClass.js] +var ; +3; diff --git a/tests/baselines/reference/privateNameNotAllowedOutsideClass.symbols b/tests/baselines/reference/privateNameNotAllowedOutsideClass.symbols new file mode 100644 index 0000000000000..b604786dda640 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAllowedOutsideClass.symbols @@ -0,0 +1,3 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts === +const #foo = 3; +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/privateNameNotAllowedOutsideClass.types b/tests/baselines/reference/privateNameNotAllowedOutsideClass.types new file mode 100644 index 0000000000000..20826f41a55e1 --- /dev/null +++ b/tests/baselines/reference/privateNameNotAllowedOutsideClass.types @@ -0,0 +1,4 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts === +const #foo = 3; +>3 : 3 + 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..82435199292ee --- /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 only accessible within 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 only accessible within 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/privateNamesInNestedClasses.js b/tests/baselines/reference/privateNamesInNestedClasses.js new file mode 100644 index 0000000000000..fc699787bfdd9 --- /dev/null +++ b/tests/baselines/reference/privateNamesInNestedClasses.js @@ -0,0 +1,33 @@ +//// [privateNamesInNestedClasses.ts] +class A { + #foo: number; + #bar: number; + method() { + class B { + #foo: string; + methodNested(a: A) { + a.#foo; // error: shadowed + a.#bar; // OK + } + } + } +} + + +//// [privateNamesInNestedClasses.js] +var A = /** @class */ (function () { + function A() { + } + A.prototype.method = function () { + var B = /** @class */ (function () { + function B() { + } + B.prototype.methodNested = function (a) { + a.#foo; // error: shadowed + a.#bar; // OK + }; + return B; + }()); + }; + return A; +}()); diff --git a/tests/baselines/reference/privateNamesInNestedClasses.symbols b/tests/baselines/reference/privateNamesInNestedClasses.symbols new file mode 100644 index 0000000000000..e9f84e3895ff9 --- /dev/null +++ b/tests/baselines/reference/privateNamesInNestedClasses.symbols @@ -0,0 +1,36 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts === +class A { +>A : Symbol(A, Decl(privateNamesInNestedClasses.ts, 0, 0)) + + #foo: number; +>#foo : Symbol(A[#foo], Decl(privateNamesInNestedClasses.ts, 0, 9)) + + #bar: number; +>#bar : Symbol(A[#bar], Decl(privateNamesInNestedClasses.ts, 1, 17)) + + method() { +>method : Symbol(A.method, Decl(privateNamesInNestedClasses.ts, 2, 17)) + + class B { +>B : Symbol(B, Decl(privateNamesInNestedClasses.ts, 3, 14)) + + #foo: string; +>#foo : Symbol(B[#foo], Decl(privateNamesInNestedClasses.ts, 4, 17)) + + methodNested(a: A) { +>methodNested : Symbol(B.methodNested, Decl(privateNamesInNestedClasses.ts, 5, 25)) +>a : Symbol(a, Decl(privateNamesInNestedClasses.ts, 6, 25)) +>A : Symbol(A, Decl(privateNamesInNestedClasses.ts, 0, 0)) + + a.#foo; // error: shadowed +>a.#foo : Symbol(A[#foo], Decl(privateNamesInNestedClasses.ts, 0, 9)) +>a : Symbol(a, Decl(privateNamesInNestedClasses.ts, 6, 25)) + + a.#bar; // OK +>a.#bar : Symbol(A[#bar], Decl(privateNamesInNestedClasses.ts, 1, 17)) +>a : Symbol(a, Decl(privateNamesInNestedClasses.ts, 6, 25)) + } + } + } +} + diff --git a/tests/baselines/reference/privateNamesInNestedClasses.types b/tests/baselines/reference/privateNamesInNestedClasses.types new file mode 100644 index 0000000000000..ea333bed37eda --- /dev/null +++ b/tests/baselines/reference/privateNamesInNestedClasses.types @@ -0,0 +1,35 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts === +class A { +>A : A + + #foo: number; +>#foo : number + + #bar: number; +>#bar : number + + method() { +>method : () => void + + class B { +>B : B + + #foo: string; +>#foo : string + + methodNested(a: A) { +>methodNested : (a: A) => void +>a : A + + a.#foo; // error: shadowed +>a.#foo : number +>a : A + + a.#bar; // OK +>a.#bar : number +>a : A + } + } + } +} + diff --git a/tests/baselines/reference/privateNamesNoAccessibilityModifiers.errors.txt b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.errors.txt new file mode 100644 index 0000000000000..5ce9be967beca --- /dev/null +++ b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts(2,12): error TS18004: Accessibility modifiers cannot be used with private names. +tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts(3,13): error TS18004: Accessibility modifiers cannot be used with private names. +tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts(4,15): error TS18004: Accessibility modifiers cannot be used with private names. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts (3 errors) ==== + class A { + public #foo; // Error + ~~~~ +!!! error TS18004: Accessibility modifiers cannot be used with private names. + private #bar; // Error + ~~~~ +!!! error TS18004: Accessibility modifiers cannot be used with private names. + protected #baz; // Error + ~~~~ +!!! error TS18004: Accessibility modifiers cannot be used with private names. + readonly #qux; // OK + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNoAccessibilityModifiers.js b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.js new file mode 100644 index 0000000000000..43227f2b84ee6 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.js @@ -0,0 +1,15 @@ +//// [privateNamesNoAccessibilityModifiers.ts] +class A { + public #foo; // Error + private #bar; // Error + protected #baz; // Error + readonly #qux; // OK +} + + +//// [privateNamesNoAccessibilityModifiers.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); diff --git a/tests/baselines/reference/privateNamesNoAccessibilityModifiers.symbols b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.symbols new file mode 100644 index 0000000000000..7586d7c5bd6c1 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.symbols @@ -0,0 +1,17 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts === +class A { +>A : Symbol(A, Decl(privateNamesNoAccessibilityModifiers.ts, 0, 0)) + + public #foo; // Error +>#foo : Symbol(A[#foo], Decl(privateNamesNoAccessibilityModifiers.ts, 0, 9)) + + private #bar; // Error +>#bar : Symbol(A[#bar], Decl(privateNamesNoAccessibilityModifiers.ts, 1, 16)) + + protected #baz; // Error +>#baz : Symbol(A[#baz], Decl(privateNamesNoAccessibilityModifiers.ts, 2, 17)) + + readonly #qux; // OK +>#qux : Symbol(A[#qux], Decl(privateNamesNoAccessibilityModifiers.ts, 3, 19)) +} + diff --git a/tests/baselines/reference/privateNamesNoAccessibilityModifiers.types b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.types new file mode 100644 index 0000000000000..fd1b35c1ded35 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoAccessibilityModifiers.types @@ -0,0 +1,17 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts === +class A { +>A : A + + public #foo; // Error +>#foo : any + + private #bar; // Error +>#bar : any + + protected #baz; // Error +>#baz : any + + readonly #qux; // OK +>#qux : any +} + diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js new file mode 100644 index 0000000000000..7d17373ace173 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.js @@ -0,0 +1,39 @@ +//// [privateNamesNoConflictWhenInheriting.ts] +class A { + #foo: number; +} + +class B extends A { + #foo: string; // OK: private names are unique to each class +} + +const b: A = new B() // OK + + +//// [privateNamesNoConflictWhenInheriting.js] +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 (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + } + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function (_super) { + __extends(B, _super); + function B() { + return _super !== null && _super.apply(this, arguments) || this; + } + return B; +}(A)); +var b = new B(); // OK diff --git a/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols new file mode 100644 index 0000000000000..11ee25651c95f --- /dev/null +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.symbols @@ -0,0 +1,21 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts === +class A { +>A : Symbol(A, Decl(privateNamesNoConflictWhenInheriting.ts, 0, 0)) + + #foo: number; +>#foo : Symbol(A[#foo], Decl(privateNamesNoConflictWhenInheriting.ts, 0, 9)) +} + +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 : 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 new file mode 100644 index 0000000000000..40459f74d2e63 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoConflictWhenInheriting.types @@ -0,0 +1,21 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts === +class A { +>A : A + + #foo: number; +>#foo : number +} + +class B extends A { +>B : B +>A : A + + #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/baselines/reference/privateNamesNoDelete.errors.txt b/tests/baselines/reference/privateNamesNoDelete.errors.txt new file mode 100644 index 0000000000000..ae45010321430 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoDelete.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts(4,16): error TS18005: The operand of a delete operator cannot be a private name. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts (1 errors) ==== + class A { + #v = 1; + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + ~~~~~~~ +!!! error TS18005: The operand of a delete operator cannot be a private name. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNoDelete.js b/tests/baselines/reference/privateNamesNoDelete.js new file mode 100644 index 0000000000000..7266285f807b5 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoDelete.js @@ -0,0 +1,17 @@ +//// [privateNamesNoDelete.ts] +class A { + #v = 1; + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + } +} + + +//// [privateNamesNoDelete.js] +var A = /** @class */ (function () { + function A() { + this.#v = 1; + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + } + return A; +}()); diff --git a/tests/baselines/reference/privateNamesNoDelete.symbols b/tests/baselines/reference/privateNamesNoDelete.symbols new file mode 100644 index 0000000000000..ae5e4315675e4 --- /dev/null +++ b/tests/baselines/reference/privateNamesNoDelete.symbols @@ -0,0 +1,14 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts === +class A { +>A : Symbol(A, Decl(privateNamesNoDelete.ts, 0, 0)) + + #v = 1; +>#v : Symbol(A[#v], Decl(privateNamesNoDelete.ts, 0, 9)) + + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. +>this.#v : Symbol(A[#v], Decl(privateNamesNoDelete.ts, 0, 9)) +>this : Symbol(A, Decl(privateNamesNoDelete.ts, 0, 0)) + } +} + diff --git a/tests/baselines/reference/privateNamesNoDelete.types b/tests/baselines/reference/privateNamesNoDelete.types new file mode 100644 index 0000000000000..d23b8712dbdcb --- /dev/null +++ b/tests/baselines/reference/privateNamesNoDelete.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts === +class A { +>A : A + + #v = 1; +>#v : number +>1 : 1 + + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. +>delete this.#v : boolean +>this.#v : number +>this : this + } +} + diff --git a/tests/baselines/reference/privateNamesNotAllowedAsParameters.errors.txt b/tests/baselines/reference/privateNamesNotAllowedAsParameters.errors.txt new file mode 100644 index 0000000000000..7d6b45dc9581c --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedAsParameters.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(2,12): error TS1138: Parameter declaration expected. +tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(2,24): error TS1005: ';' expected. +tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(2,26): error TS1068: Unexpected token. A constructor, method, accessor, or property was expected. +tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts(3,1): error TS1128: Declaration or statement expected. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts (4 errors) ==== + class A { + setFoo(#foo: string) {} + ~~~~ +!!! error TS1138: Parameter declaration expected. + ~ +!!! error TS1005: ';' expected. + ~ +!!! error TS1068: Unexpected token. A constructor, method, accessor, or property was expected. + } + ~ +!!! error TS1128: Declaration or statement expected. + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNotAllowedAsParameters.js b/tests/baselines/reference/privateNamesNotAllowedAsParameters.js new file mode 100644 index 0000000000000..862409a851765 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedAsParameters.js @@ -0,0 +1,14 @@ +//// [privateNamesNotAllowedAsParameters.ts] +class A { + setFoo(#foo: string) {} +} + + +//// [privateNamesNotAllowedAsParameters.js] +var A = /** @class */ (function () { + function A() { + } + A.prototype.setFoo = function () { }; + return A; +}()); +{ } diff --git a/tests/baselines/reference/privateNamesNotAllowedAsParameters.symbols b/tests/baselines/reference/privateNamesNotAllowedAsParameters.symbols new file mode 100644 index 0000000000000..013e0e192734c --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedAsParameters.symbols @@ -0,0 +1,9 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts === +class A { +>A : Symbol(A, Decl(privateNamesNotAllowedAsParameters.ts, 0, 0)) + + setFoo(#foo: string) {} +>setFoo : Symbol(A.setFoo, Decl(privateNamesNotAllowedAsParameters.ts, 0, 9)) +>#foo : Symbol(A[#foo], Decl(privateNamesNotAllowedAsParameters.ts, 1, 11)) +} + diff --git a/tests/baselines/reference/privateNamesNotAllowedAsParameters.types b/tests/baselines/reference/privateNamesNotAllowedAsParameters.types new file mode 100644 index 0000000000000..b11ecd42efe52 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedAsParameters.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts === +class A { +>A : A + + setFoo(#foo: string) {} +>setFoo : () => any +>#foo : string +} + diff --git a/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.errors.txt b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.errors.txt new file mode 100644 index 0000000000000..ad967f6b8c0ce --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.errors.txt @@ -0,0 +1,13 @@ +tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts(1,7): error TS1134: Variable declaration expected. +tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts(1,12): error TS1134: Variable declaration expected. +tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts(1,14): error TS1134: Variable declaration expected. + + +==== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts (3 errors) ==== + const #foo = 3; + ~~~~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.js b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.js new file mode 100644 index 0000000000000..9b65ff8a3a0b0 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.js @@ -0,0 +1,6 @@ +//// [privateNamesNotAllowedInVariableDeclarations.ts] +const #foo = 3; + +//// [privateNamesNotAllowedInVariableDeclarations.js] +var ; +3; diff --git a/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.symbols b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.symbols new file mode 100644 index 0000000000000..b9b048bea1fb0 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.symbols @@ -0,0 +1,3 @@ +=== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts === +const #foo = 3; +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.types b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.types new file mode 100644 index 0000000000000..6c52944e553c7 --- /dev/null +++ b/tests/baselines/reference/privateNamesNotAllowedInVariableDeclarations.types @@ -0,0 +1,4 @@ +=== tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts === +const #foo = 3; +>3 : 3 + diff --git a/tests/baselines/reference/privateNamesUnique.errors.txt b/tests/baselines/reference/privateNamesUnique.errors.txt new file mode 100644 index 0000000000000..43b7b7790e5d4 --- /dev/null +++ b/tests/baselines/reference/privateNamesUnique.errors.txt @@ -0,0 +1,18 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts(9,7): error TS2322: Type 'B' is not assignable to type 'A'. + Property '#foo' is missing in type 'B'. + + +==== tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts (1 errors) ==== + class A { + #foo: number; + } + + class B { + #foo: number; + } + + const b: A = new B() // Error: Property #foo is missing + ~ +!!! error TS2322: Type 'B' is not assignable to type 'A'. +!!! error TS2322: Property '#foo' is missing in type 'B'. + \ No newline at end of file diff --git a/tests/baselines/reference/privateNamesUnique.js b/tests/baselines/reference/privateNamesUnique.js new file mode 100644 index 0000000000000..a5b5a2dad7b3e --- /dev/null +++ b/tests/baselines/reference/privateNamesUnique.js @@ -0,0 +1,24 @@ +//// [privateNamesUnique.ts] +class A { + #foo: number; +} + +class B { + #foo: number; +} + +const b: A = new B() // Error: Property #foo is missing + + +//// [privateNamesUnique.js] +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function () { + function B() { + } + return B; +}()); +var b = new B(); // Error: Property #foo is missing diff --git a/tests/baselines/reference/privateNamesUnique.symbols b/tests/baselines/reference/privateNamesUnique.symbols new file mode 100644 index 0000000000000..224785a388fca --- /dev/null +++ b/tests/baselines/reference/privateNamesUnique.symbols @@ -0,0 +1,20 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts === +class A { +>A : Symbol(A, Decl(privateNamesUnique.ts, 0, 0)) + + #foo: number; +>#foo : Symbol(A[#foo], Decl(privateNamesUnique.ts, 0, 9)) +} + +class B { +>B : Symbol(B, Decl(privateNamesUnique.ts, 2, 1)) + + #foo: number; +>#foo : Symbol(B[#foo], Decl(privateNamesUnique.ts, 4, 9)) +} + +const b: A = new B() // Error: Property #foo is missing +>b : Symbol(b, Decl(privateNamesUnique.ts, 8, 5)) +>A : Symbol(A, Decl(privateNamesUnique.ts, 0, 0)) +>B : Symbol(B, Decl(privateNamesUnique.ts, 2, 1)) + diff --git a/tests/baselines/reference/privateNamesUnique.types b/tests/baselines/reference/privateNamesUnique.types new file mode 100644 index 0000000000000..16fdb5a6f1629 --- /dev/null +++ b/tests/baselines/reference/privateNamesUnique.types @@ -0,0 +1,20 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts === +class A { +>A : A + + #foo: number; +>#foo : number +} + +class B { +>B : B + + #foo: number; +>#foo : number +} + +const b: A = new B() // Error: Property #foo is missing +>b : A +>new B() : B +>B : typeof B + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts b/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts index d4c0b8ad46efb..0efb1813fcefa 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNameAndIndexSignature.ts @@ -1,6 +1,6 @@ -class A { - [k: string]: any; - constructor(message: string) { - this.#f = 3 // Error Property '#f' does not exist on type 'A'. - } -} +class A { + [k: string]: any; + constructor(message: string) { + this.#f = 3 // Error Property '#f' does not exist on type 'A'. + } +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts b/tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts new file mode 100644 index 0000000000000..4a4c1525c852a --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts @@ -0,0 +1,7 @@ +class A { + #constructor() {} // Error: `#constructor` is a reserved word. +} + +class A { + #constructor = 5 // Error: `#constructor` is a reserved word. +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameField.ts b/tests/cases/conformance/classes/members/privateNames/privateNameField.ts index 02e449fb3e002..3d38a3d651453 100644 --- a/tests/cases/conformance/classes/members/privateNames/privateNameField.ts +++ b/tests/cases/conformance/classes/members/privateNames/privateNameField.ts @@ -1,6 +1,6 @@ -class A { - #name: string; - constructor(name: string) { - this.#name = name; - } +class A { + #name: string; + constructor(name: string) { + this.#name = name; + } } \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts b/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts new file mode 100644 index 0000000000000..1d213d7e54509 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts @@ -0,0 +1,5 @@ +class A { + #foo: number = 3; +} + +new A().#foo = 4; // Error diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts b/tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts new file mode 100644 index 0000000000000..7af2bf989ff3b --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameNotAllowedOutsideClass.ts @@ -0,0 +1 @@ +const #foo = 3; \ No newline at end of file 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/privateNamesInNestedClasses.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts new file mode 100644 index 0000000000000..7b38006930eab --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesInNestedClasses.ts @@ -0,0 +1,13 @@ +class A { + #foo: number; + #bar: number; + method() { + class B { + #foo: string; + methodNested(a: A) { + a.#foo; // error: shadowed + a.#bar; // OK + } + } + } +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts new file mode 100644 index 0000000000000..cd3f748196950 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts @@ -0,0 +1,6 @@ +class A { + public #foo; // Error + private #bar; // Error + protected #baz; // Error + readonly #qux; // OK +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts new file mode 100644 index 0000000000000..bb55edd9b3dfc --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts @@ -0,0 +1,9 @@ +class A { + #foo: number; +} + +class B extends A { + #foo: string; // OK: private names are unique to each class +} + +const b: A = new B() // OK diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts new file mode 100644 index 0000000000000..a71a733371023 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts @@ -0,0 +1,6 @@ +class A { + #v = 1; + constructor() { + delete this.#v; // Error: The operand of a delete operator cannot be a private name. + } +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts new file mode 100644 index 0000000000000..edc846a0bf35d --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsParameters.ts @@ -0,0 +1,3 @@ +class A { + setFoo(#foo: string) {} +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts b/tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts new file mode 100644 index 0000000000000..cee206eacd201 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts @@ -0,0 +1,9 @@ +class A { + #foo: number; +} + +class B { + #foo: number; +} + +const b: A = new B() // Error: Property #foo is missing diff --git a/tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts b/tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts new file mode 100644 index 0000000000000..7af2bf989ff3b --- /dev/null +++ b/tests/cases/conformance/classes/privateNames/privateNamesNotAllowedInVariableDeclarations.ts @@ -0,0 +1 @@ +const #foo = 3; \ No newline at end of file