@@ -1523,8 +1523,8 @@ namespace ts {
1523
1523
}
1524
1524
}
1525
1525
1526
- function diagnosticName(nameArg: __String | Identifier) {
1527
- return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier);
1526
+ function diagnosticName(nameArg: __String | Identifier | PrivateName ) {
1527
+ return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier | PrivateName );
1528
1528
}
1529
1529
1530
1530
function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
@@ -2594,15 +2594,16 @@ namespace ts {
2594
2594
return getUnionType(arrayFrom(typeofEQFacts.keys(), getLiteralType));
2595
2595
}
2596
2596
2597
- // A reserved member name starts with two underscores, but the third character cannot be an underscore
2598
- // or the @ symbol . A third underscore indicates an escaped form of an identifer that started
2597
+ // A reserved member name starts with two underscores, but the third character cannot be an underscore,
2598
+ // @ or # . A third underscore indicates an escaped form of an identifer that started
2599
2599
// with at least two underscores. The @ character indicates that the name is denoted by a well known ES
2600
- // Symbol instance.
2600
+ // Symbol instance and the # indicates that the name is a PrivateName .
2601
2601
function isReservedMemberName(name: __String) {
2602
2602
return (name as string).charCodeAt(0) === CharacterCodes._ &&
2603
2603
(name as string).charCodeAt(1) === CharacterCodes._ &&
2604
2604
(name as string).charCodeAt(2) !== CharacterCodes._ &&
2605
- (name as string).charCodeAt(2) !== CharacterCodes.at;
2605
+ (name as string).charCodeAt(2) !== CharacterCodes.at &&
2606
+ (name as string).charCodeAt(2) !== CharacterCodes.hash;
2606
2607
}
2607
2608
2608
2609
function getNamedMembers(members: SymbolTable): Symbol[] {
@@ -9042,7 +9043,9 @@ namespace ts {
9042
9043
}
9043
9044
9044
9045
function getLiteralTypeFromPropertyName(prop: Symbol, include: TypeFlags) {
9045
- if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
9046
+ const hasNonPublicModifier = !!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier);
9047
+ const hasPrivateName = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) && isPrivateName(prop.valueDeclaration.name);
9048
+ if (!hasNonPublicModifier && !hasPrivateName) {
9046
9049
let type = getLateBoundSymbol(prop).nameType;
9047
9050
if (!type && !isKnownSymbol(prop)) {
9048
9051
const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration);
@@ -11850,7 +11853,28 @@ namespace ts {
11850
11853
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties);
11851
11854
if (unmatchedProperty) {
11852
11855
if (reportErrors) {
11853
- reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(unmatchedProperty), typeToString(source));
11856
+ let hasReported = false;
11857
+ // give specific error in case where private names have the same description
11858
+ if (
11859
+ unmatchedProperty.valueDeclaration
11860
+ && isNamedDeclaration(unmatchedProperty.valueDeclaration)
11861
+ && isPrivateName(unmatchedProperty.valueDeclaration.name)
11862
+ && isClassDeclaration(source.symbol.valueDeclaration)
11863
+ ) {
11864
+ const privateNameDescription = unmatchedProperty.valueDeclaration.name.escapedText;
11865
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(source.symbol, privateNameDescription);
11866
+ if (symbolTableKey && !!getPropertyOfType(source, symbolTableKey)) {
11867
+ reportError(
11868
+ 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,
11869
+ diagnosticName(privateNameDescription),
11870
+ diagnosticName(source.symbol.valueDeclaration.name || ("anonymous" as __String))
11871
+ );
11872
+ hasReported = true;
11873
+ }
11874
+ }
11875
+ if (!hasReported) {
11876
+ reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(unmatchedProperty), typeToString(source));
11877
+ }
11854
11878
}
11855
11879
return Ternary.False;
11856
11880
}
@@ -17974,6 +17998,46 @@ namespace ts {
17974
17998
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right);
17975
17999
}
17976
18000
18001
+ function getPropertyByPrivateName(apparentType: Type, leftType: Type, right: PrivateName): Symbol | undefined {
18002
+ let classWithShadowedPrivateName;
18003
+ let klass = getContainingClass(right);
18004
+ while (klass) {
18005
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(klass.symbol, right.escapedText);
18006
+ if (symbolTableKey) {
18007
+ const prop = getPropertyOfType(apparentType, symbolTableKey);
18008
+ if (prop) {
18009
+ if (classWithShadowedPrivateName) {
18010
+ error(
18011
+ right,
18012
+ 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,
18013
+ diagnosticName(right),
18014
+ diagnosticName(classWithShadowedPrivateName.name || ("anonymous" as __String))
18015
+ );
18016
+ return undefined;
18017
+ }
18018
+ return prop;
18019
+ }
18020
+ else {
18021
+ classWithShadowedPrivateName = klass;
18022
+ }
18023
+ }
18024
+ klass = getContainingClass(klass);
18025
+ }
18026
+ // If this isn't a case of shadowing, and the lhs has a property with the same
18027
+ // private name description, then there is a privacy violation
18028
+ if (leftType.symbol.members) {
18029
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(leftType.symbol, right.escapedText);
18030
+ if (symbolTableKey) {
18031
+ const prop = getPropertyOfType(apparentType, symbolTableKey);
18032
+ if (prop) {
18033
+ error(right, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_name, symbolToString(prop), typeToString(getDeclaringClass(prop)!));
18034
+ }
18035
+ }
18036
+ }
18037
+ // not found
18038
+ return undefined;
18039
+ }
18040
+
17977
18041
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier | PrivateName) {
17978
18042
let propType: Type;
17979
18043
const leftType = checkNonNullExpression(left);
@@ -17986,7 +18050,7 @@ namespace ts {
17986
18050
return apparentType;
17987
18051
}
17988
18052
const assignmentKind = getAssignmentTargetKind(node);
17989
- const prop = getPropertyOfType(apparentType, right.escapedText);
18053
+ const prop = isPrivateName(right) ? getPropertyByPrivateName(apparentType, leftType, right) : getPropertyOfType(apparentType, right.escapedText);
17990
18054
if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
17991
18055
markAliasReferenced(parentSymbol, node);
17992
18056
}
@@ -20725,10 +20789,16 @@ namespace ts {
20725
20789
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
20726
20790
return booleanType;
20727
20791
}
20792
+ if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) {
20793
+ error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name);
20794
+
20795
+ }
20728
20796
const links = getNodeLinks(expr);
20729
20797
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
20730
- if (symbol && isReadonlySymbol(symbol)) {
20731
- error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
20798
+ if (symbol) {
20799
+ if (isReadonlySymbol(symbol)) {
20800
+ error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
20801
+ }
20732
20802
}
20733
20803
return booleanType;
20734
20804
}
@@ -21878,9 +21948,6 @@ namespace ts {
21878
21948
checkGrammarDecoratorsAndModifiers(node);
21879
21949
21880
21950
checkVariableLikeDeclaration(node);
21881
- if (node.name && isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
21882
- error(node, Diagnostics.Private_names_cannot_be_used_as_parameters);
21883
- }
21884
21951
const func = getContainingFunction(node)!;
21885
21952
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
21886
21953
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
@@ -28515,6 +28582,9 @@ namespace ts {
28515
28582
else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (<ParameterDeclaration>node).dotDotDotToken) {
28516
28583
return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter);
28517
28584
}
28585
+ else if (isNamedDeclaration(node) && (flags & ModifierFlags.AccessibilityModifier) && node.name.kind === SyntaxKind.PrivateName) {
28586
+ return grammarErrorOnNode(node, Diagnostics.Accessibility_modifiers_cannot_be_used_with_private_names);
28587
+ }
28518
28588
if (flags & ModifierFlags.Async) {
28519
28589
return checkGrammarAsyncModifier(node, lastAsync!);
28520
28590
}
@@ -29293,10 +29363,6 @@ namespace ts {
29293
29363
checkESModuleMarker(node.name);
29294
29364
}
29295
29365
29296
- if (isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
29297
- return grammarErrorOnNode(node.name, Diagnostics.Private_names_are_not_allowed_in_variable_declarations);
29298
- }
29299
-
29300
29366
const checkLetConstNames = (isLet(node) || isVarConst(node));
29301
29367
29302
29368
// 1. LexicalDeclaration : LetOrConst BindingList ;
0 commit comments