@@ -132,6 +132,7 @@ namespace ts {
132132 getDeclaredTypeOfSymbol,
133133 getPropertiesOfType,
134134 getPropertyOfType: (type, name) => getPropertyOfType(type, escapeLeadingUnderscores(name)),
135+ getPropertyForPrivateName,
135136 getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)),
136137 getIndexInfoOfType,
137138 getSignaturesOfType,
@@ -1656,8 +1657,8 @@ namespace ts {
16561657 }
16571658 }
16581659
1659- function diagnosticName(nameArg: __String | Identifier) {
1660- return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier);
1660+ function diagnosticName(nameArg: __String | Identifier | PrivateName ) {
1661+ return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier | PrivateName );
16611662 }
16621663
16631664 function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
@@ -2839,15 +2840,16 @@ namespace ts {
28392840 return type;
28402841 }
28412842
2842- // A reserved member name starts with two underscores, but the third character cannot be an underscore
2843- // or the @ symbol . A third underscore indicates an escaped form of an identifer that started
2843+ // A reserved member name starts with two underscores, but the third character cannot be an underscore,
2844+ // @, or # . A third underscore indicates an escaped form of an identifer that started
28442845 // with at least two underscores. The @ character indicates that the name is denoted by a well known ES
2845- // Symbol instance.
2846+ // Symbol instance and the # indicates that the name is a PrivateName .
28462847 function isReservedMemberName(name: __String) {
28472848 return (name as string).charCodeAt(0) === CharacterCodes._ &&
28482849 (name as string).charCodeAt(1) === CharacterCodes._ &&
28492850 (name as string).charCodeAt(2) !== CharacterCodes._ &&
2850- (name as string).charCodeAt(2) !== CharacterCodes.at;
2851+ (name as string).charCodeAt(2) !== CharacterCodes.at &&
2852+ (name as string).charCodeAt(2) !== CharacterCodes.hash;
28512853 }
28522854
28532855 function getNamedMembers(members: SymbolTable): Symbol[] {
@@ -6554,7 +6556,7 @@ namespace ts {
65546556 */
65556557 function getPropertyNameFromType(type: StringLiteralType | NumberLiteralType | UniqueESSymbolType): __String {
65566558 if (type.flags & TypeFlags.UniqueESSymbol) {
6557- return (<UniqueESSymbolType> type).escapedName ;
6559+ return getPropertyNameForUniqueESSymbol( type.symbol) ;
65586560 }
65596561 if (type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
65606562 return escapeLeadingUnderscores("" + (<StringLiteralType | NumberLiteralType>type).value);
@@ -9801,6 +9803,9 @@ namespace ts {
98019803 }
98029804
98039805 function getLiteralTypeFromPropertyName(name: PropertyName) {
9806+ if (isPrivateName(name)) {
9807+ return neverType;
9808+ }
98049809 return isIdentifier(name) ? getLiteralType(unescapeLeadingUnderscores(name.escapedText)) :
98059810 getRegularTypeOfLiteralType(isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name));
98069811 }
@@ -13091,23 +13096,44 @@ namespace ts {
1309113096 const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
1309213097 if (unmatchedProperty) {
1309313098 if (reportErrors) {
13094- const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false));
13095- if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code &&
13096- headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) {
13097- suppressNextError = true; // Retain top-level error for interface implementing issues, otherwise omit it
13098- }
13099- if (props.length === 1) {
13100- const propName = symbolToString(unmatchedProperty);
13101- reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, typeToString(source), typeToString(target));
13102- if (length(unmatchedProperty.declarations)) {
13103- associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations[0], Diagnostics._0_is_declared_here, propName));
13099+ let hasReported = false;
13100+ // give specific error in case where private names have the same description
13101+ if (
13102+ unmatchedProperty.valueDeclaration
13103+ && isNamedDeclaration(unmatchedProperty.valueDeclaration)
13104+ && isPrivateName(unmatchedProperty.valueDeclaration.name)
13105+ && isClassDeclaration(source.symbol.valueDeclaration)
13106+ ) {
13107+ const privateNameDescription = unmatchedProperty.valueDeclaration.name.escapedText;
13108+ const symbolTableKey = getPropertyNameForPrivateNameDescription(source.symbol, privateNameDescription);
13109+ if (symbolTableKey && !!getPropertyOfType(source, symbolTableKey)) {
13110+ reportError(
13111+ Diagnostics.Property_0_is_missing_in_type_1_While_type_1_has_a_private_member_with_the_same_spelling_its_declaration_and_accessibility_are_distinct,
13112+ diagnosticName(privateNameDescription),
13113+ diagnosticName(source.symbol.valueDeclaration.name || ("(anonymous)" as __String))
13114+ );
13115+ hasReported = true;
1310413116 }
1310513117 }
13106- else if (props.length > 5) { // arbitrary cutoff for too-long list form
13107- reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4);
13108- }
13109- else {
13110- reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
13118+ if (!hasReported) {
13119+ const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false));
13120+ if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code &&
13121+ headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) {
13122+ suppressNextError = true; // Retain top-level error for interface implementing issues, otherwise omit it
13123+ }
13124+ if (props.length === 1) {
13125+ const propName = symbolToString(unmatchedProperty);
13126+ reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, typeToString(source), typeToString(target));
13127+ if (length(unmatchedProperty.declarations)) {
13128+ associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations[0], Diagnostics._0_is_declared_here, propName));
13129+ }
13130+ }
13131+ else if (props.length > 5) { // arbitrary cutoff for too-long list form
13132+ reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4);
13133+ }
13134+ else {
13135+ reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
13136+ }
1311113137 }
1311213138 }
1311313139 return Ternary.False;
@@ -19593,6 +19619,48 @@ namespace ts {
1959319619 return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right);
1959419620 }
1959519621
19622+ function getPropertyForPrivateName(apparentType: Type, leftType: Type, right: PrivateName, errorNode: Node | undefined): Symbol | undefined {
19623+ let classWithShadowedPrivateName;
19624+ let container = getContainingClass(right);
19625+ while (container) {
19626+ const symbolTableKey = getPropertyNameForPrivateNameDescription(container.symbol, right.escapedText);
19627+ if (symbolTableKey) {
19628+ const prop = getPropertyOfType(apparentType, symbolTableKey);
19629+ if (prop) {
19630+ if (classWithShadowedPrivateName) {
19631+ if (errorNode) {
19632+ error(
19633+ errorNode,
19634+ Diagnostics.This_usage_of_0_refers_to_the_private_member_declared_in_its_enclosing_class_While_type_1_has_a_private_member_with_the_same_spelling_its_declaration_and_accessibility_are_distinct,
19635+ diagnosticName(right),
19636+ diagnosticName(classWithShadowedPrivateName.name || ("(anonymous)" as __String))
19637+ );
19638+ }
19639+ return undefined;
19640+ }
19641+ return prop;
19642+ }
19643+ else {
19644+ classWithShadowedPrivateName = container;
19645+ }
19646+ }
19647+ container = getContainingClass(container);
19648+ }
19649+ // If this isn't a case of shadowing, and the lhs has a property with the same
19650+ // private name description, then there is a privacy violation
19651+ if (leftType.symbol.members) {
19652+ const symbolTableKey = getPropertyNameForPrivateNameDescription(leftType.symbol, right.escapedText);
19653+ const prop = getPropertyOfType(apparentType, symbolTableKey);
19654+ if (prop) {
19655+ if (errorNode) {
19656+ error(right, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_name, symbolToString(prop), typeToString(getDeclaringClass(prop)!));
19657+ }
19658+ }
19659+ }
19660+ // not found
19661+ return undefined;
19662+ }
19663+
1959619664 function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier | PrivateName) {
1959719665 let propType: Type;
1959819666 const leftType = checkNonNullExpression(left);
@@ -19605,7 +19673,7 @@ namespace ts {
1960519673 return apparentType;
1960619674 }
1960719675 const assignmentKind = getAssignmentTargetKind(node);
19608- const prop = getPropertyOfType(apparentType, right.escapedText);
19676+ const prop = isPrivateName(right) ? getPropertyForPrivateName(apparentType, leftType, right, /* errorNode */ right) : getPropertyOfType(apparentType, right.escapedText);
1960919677 if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
1961019678 markAliasReferenced(parentSymbol, node);
1961119679 }
@@ -22625,6 +22693,9 @@ namespace ts {
2262522693 error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
2262622694 return booleanType;
2262722695 }
22696+ if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) {
22697+ error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name);
22698+ }
2262822699 const links = getNodeLinks(expr);
2262922700 const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
2263022701 if (symbol && isReadonlySymbol(symbol)) {
@@ -23936,9 +24007,6 @@ namespace ts {
2393624007 checkGrammarDecoratorsAndModifiers(node);
2393724008
2393824009 checkVariableLikeDeclaration(node);
23939- if (node.name && isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
23940- error(node, Diagnostics.Private_names_cannot_be_used_as_parameters);
23941- }
2394224010 const func = getContainingFunction(node)!;
2394324011 if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
2394424012 if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
@@ -30695,6 +30763,9 @@ namespace ts {
3069530763 else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (<ParameterDeclaration>node).dotDotDotToken) {
3069630764 return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter);
3069730765 }
30766+ else if (isNamedDeclaration(node) && (flags & ModifierFlags.AccessibilityModifier) && node.name.kind === SyntaxKind.PrivateName) {
30767+ return grammarErrorOnNode(node, Diagnostics.Accessibility_modifiers_cannot_be_used_with_private_names);
30768+ }
3069830769 if (flags & ModifierFlags.Async) {
3069930770 return checkGrammarAsyncModifier(node, lastAsync!);
3070030771 }
@@ -31092,6 +31163,10 @@ namespace ts {
3109231163 return grammarErrorOnNode(prop.equalsToken!, Diagnostics.can_only_be_used_in_an_object_literal_property_inside_a_destructuring_assignment);
3109331164 }
3109431165
31166+ if (name.kind === SyntaxKind.PrivateName) {
31167+ return grammarErrorOnNode(name, Diagnostics.Private_names_are_not_allowed_outside_class_bodies);
31168+ }
31169+
3109531170 // Modifiers are never allowed on properties except for 'async' on a method declaration
3109631171 if (prop.modifiers) {
3109731172 for (const mod of prop.modifiers!) { // TODO: GH#19955
@@ -31533,10 +31608,6 @@ namespace ts {
3153331608 checkESModuleMarker(node.name);
3153431609 }
3153531610
31536- if (isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
31537- return grammarErrorOnNode(node.name, Diagnostics.Private_names_are_not_allowed_in_variable_declarations);
31538- }
31539-
3154031611 const checkLetConstNames = (isLet(node) || isVarConst(node));
3154131612
3154231613 // 1. LexicalDeclaration : LetOrConst BindingList ;
0 commit comments