@@ -132,6 +132,7 @@ namespace ts {
132
132
getDeclaredTypeOfSymbol,
133
133
getPropertiesOfType,
134
134
getPropertyOfType: (type, name) => getPropertyOfType(type, escapeLeadingUnderscores(name)),
135
+ getPropertyForPrivateName,
135
136
getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)),
136
137
getIndexInfoOfType,
137
138
getSignaturesOfType,
@@ -1656,8 +1657,8 @@ namespace ts {
1656
1657
}
1657
1658
}
1658
1659
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 );
1661
1662
}
1662
1663
1663
1664
function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
@@ -2839,15 +2840,16 @@ namespace ts {
2839
2840
return type;
2840
2841
}
2841
2842
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
2844
2845
// 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 .
2846
2847
function isReservedMemberName(name: __String) {
2847
2848
return (name as string).charCodeAt(0) === CharacterCodes._ &&
2848
2849
(name as string).charCodeAt(1) === CharacterCodes._ &&
2849
2850
(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;
2851
2853
}
2852
2854
2853
2855
function getNamedMembers(members: SymbolTable): Symbol[] {
@@ -6554,7 +6556,7 @@ namespace ts {
6554
6556
*/
6555
6557
function getPropertyNameFromType(type: StringLiteralType | NumberLiteralType | UniqueESSymbolType): __String {
6556
6558
if (type.flags & TypeFlags.UniqueESSymbol) {
6557
- return (<UniqueESSymbolType> type).escapedName ;
6559
+ return getPropertyNameForUniqueESSymbol( type.symbol) ;
6558
6560
}
6559
6561
if (type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
6560
6562
return escapeLeadingUnderscores("" + (<StringLiteralType | NumberLiteralType>type).value);
@@ -9801,6 +9803,9 @@ namespace ts {
9801
9803
}
9802
9804
9803
9805
function getLiteralTypeFromPropertyName(name: PropertyName) {
9806
+ if (isPrivateName(name)) {
9807
+ return neverType;
9808
+ }
9804
9809
return isIdentifier(name) ? getLiteralType(unescapeLeadingUnderscores(name.escapedText)) :
9805
9810
getRegularTypeOfLiteralType(isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name));
9806
9811
}
@@ -13091,23 +13096,44 @@ namespace ts {
13091
13096
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
13092
13097
if (unmatchedProperty) {
13093
13098
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;
13104
13116
}
13105
13117
}
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
+ }
13111
13137
}
13112
13138
}
13113
13139
return Ternary.False;
@@ -19593,6 +19619,48 @@ namespace ts {
19593
19619
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right);
19594
19620
}
19595
19621
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
+
19596
19664
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier | PrivateName) {
19597
19665
let propType: Type;
19598
19666
const leftType = checkNonNullExpression(left);
@@ -19605,7 +19673,7 @@ namespace ts {
19605
19673
return apparentType;
19606
19674
}
19607
19675
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);
19609
19677
if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
19610
19678
markAliasReferenced(parentSymbol, node);
19611
19679
}
@@ -22625,6 +22693,9 @@ namespace ts {
22625
22693
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
22626
22694
return booleanType;
22627
22695
}
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
+ }
22628
22699
const links = getNodeLinks(expr);
22629
22700
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
22630
22701
if (symbol && isReadonlySymbol(symbol)) {
@@ -23936,9 +24007,6 @@ namespace ts {
23936
24007
checkGrammarDecoratorsAndModifiers(node);
23937
24008
23938
24009
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
- }
23942
24010
const func = getContainingFunction(node)!;
23943
24011
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
23944
24012
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
@@ -30695,6 +30763,9 @@ namespace ts {
30695
30763
else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (<ParameterDeclaration>node).dotDotDotToken) {
30696
30764
return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter);
30697
30765
}
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
+ }
30698
30769
if (flags & ModifierFlags.Async) {
30699
30770
return checkGrammarAsyncModifier(node, lastAsync!);
30700
30771
}
@@ -31092,6 +31163,10 @@ namespace ts {
31092
31163
return grammarErrorOnNode(prop.equalsToken!, Diagnostics.can_only_be_used_in_an_object_literal_property_inside_a_destructuring_assignment);
31093
31164
}
31094
31165
31166
+ if (name.kind === SyntaxKind.PrivateName) {
31167
+ return grammarErrorOnNode(name, Diagnostics.Private_names_are_not_allowed_outside_class_bodies);
31168
+ }
31169
+
31095
31170
// Modifiers are never allowed on properties except for 'async' on a method declaration
31096
31171
if (prop.modifiers) {
31097
31172
for (const mod of prop.modifiers!) { // TODO: GH#19955
@@ -31533,10 +31608,6 @@ namespace ts {
31533
31608
checkESModuleMarker(node.name);
31534
31609
}
31535
31610
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
-
31540
31611
const checkLetConstNames = (isLet(node) || isVarConst(node));
31541
31612
31542
31613
// 1. LexicalDeclaration : LetOrConst BindingList ;
0 commit comments