@@ -122,6 +122,7 @@ namespace ts {
122
122
getDeclaredTypeOfSymbol,
123
123
getPropertiesOfType,
124
124
getPropertyOfType: (type, name) => getPropertyOfType(type, escapeLeadingUnderscores(name)),
125
+ getPropertyForPrivateName,
125
126
getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)),
126
127
getIndexInfoOfType,
127
128
getSignaturesOfType,
@@ -1572,8 +1573,8 @@ namespace ts {
1572
1573
}
1573
1574
}
1574
1575
1575
- function diagnosticName(nameArg: __String | Identifier) {
1576
- return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier);
1576
+ function diagnosticName(nameArg: __String | Identifier | PrivateName ) {
1577
+ return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier | PrivateName );
1577
1578
}
1578
1579
1579
1580
function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
@@ -2679,15 +2680,16 @@ namespace ts {
2679
2680
return getUnionType(arrayFrom(typeofEQFacts.keys(), getLiteralType));
2680
2681
}
2681
2682
2682
- // A reserved member name starts with two underscores, but the third character cannot be an underscore
2683
- // or the @ symbol . A third underscore indicates an escaped form of an identifer that started
2683
+ // A reserved member name starts with two underscores, but the third character cannot be an underscore,
2684
+ // @, or # . A third underscore indicates an escaped form of an identifer that started
2684
2685
// with at least two underscores. The @ character indicates that the name is denoted by a well known ES
2685
- // Symbol instance.
2686
+ // Symbol instance and the # indicates that the name is a PrivateName .
2686
2687
function isReservedMemberName(name: __String) {
2687
2688
return (name as string).charCodeAt(0) === CharacterCodes._ &&
2688
2689
(name as string).charCodeAt(1) === CharacterCodes._ &&
2689
2690
(name as string).charCodeAt(2) !== CharacterCodes._ &&
2690
- (name as string).charCodeAt(2) !== CharacterCodes.at;
2691
+ (name as string).charCodeAt(2) !== CharacterCodes.at &&
2692
+ (name as string).charCodeAt(2) !== CharacterCodes.hash;
2691
2693
}
2692
2694
2693
2695
function getNamedMembers(members: SymbolTable): Symbol[] {
@@ -6250,7 +6252,7 @@ namespace ts {
6250
6252
*/
6251
6253
function getLateBoundNameFromType(type: LiteralType | UniqueESSymbolType): __String {
6252
6254
if (type.flags & TypeFlags.UniqueESSymbol) {
6253
- return `__@${type.symbol.escapedName}@${getSymbolId (type.symbol)}` as __String ;
6255
+ return getPropertyNameForUniqueESSymbol (type.symbol);
6254
6256
}
6255
6257
if (type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
6256
6258
return escapeLeadingUnderscores("" + (<LiteralType>type).value);
@@ -9258,7 +9260,9 @@ namespace ts {
9258
9260
}
9259
9261
9260
9262
function getLiteralTypeFromPropertyName(prop: Symbol, include: TypeFlags) {
9261
- if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
9263
+ const hasNonPublicModifier = !!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier);
9264
+ const hasPrivateName = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) && isPrivateName(prop.valueDeclaration.name);
9265
+ if (!hasNonPublicModifier && !hasPrivateName) {
9262
9266
let type = getLateBoundSymbol(prop).nameType;
9263
9267
if (!type && !isKnownSymbol(prop)) {
9264
9268
const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration);
@@ -12205,7 +12209,28 @@ namespace ts {
12205
12209
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties);
12206
12210
if (unmatchedProperty) {
12207
12211
if (reportErrors) {
12208
- reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(unmatchedProperty), typeToString(source));
12212
+ let hasReported = false;
12213
+ // give specific error in case where private names have the same description
12214
+ if (
12215
+ unmatchedProperty.valueDeclaration
12216
+ && isNamedDeclaration(unmatchedProperty.valueDeclaration)
12217
+ && isPrivateName(unmatchedProperty.valueDeclaration.name)
12218
+ && isClassDeclaration(source.symbol.valueDeclaration)
12219
+ ) {
12220
+ const privateNameDescription = unmatchedProperty.valueDeclaration.name.escapedText;
12221
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(source.symbol, privateNameDescription);
12222
+ if (symbolTableKey && !!getPropertyOfType(source, symbolTableKey)) {
12223
+ reportError(
12224
+ 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,
12225
+ diagnosticName(privateNameDescription),
12226
+ diagnosticName(source.symbol.valueDeclaration.name || ("(anonymous)" as __String))
12227
+ );
12228
+ hasReported = true;
12229
+ }
12230
+ }
12231
+ if (!hasReported) {
12232
+ reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(unmatchedProperty), typeToString(source));
12233
+ }
12209
12234
}
12210
12235
return Ternary.False;
12211
12236
}
@@ -18423,6 +18448,48 @@ namespace ts {
18423
18448
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right);
18424
18449
}
18425
18450
18451
+ function getPropertyForPrivateName(apparentType: Type, leftType: Type, right: PrivateName, errorNode: Node | undefined): Symbol | undefined {
18452
+ let classWithShadowedPrivateName;
18453
+ let container = getContainingClass(right);
18454
+ while (container) {
18455
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(container.symbol, right.escapedText);
18456
+ if (symbolTableKey) {
18457
+ const prop = getPropertyOfType(apparentType, symbolTableKey);
18458
+ if (prop) {
18459
+ if (classWithShadowedPrivateName) {
18460
+ if (errorNode) {
18461
+ error(
18462
+ errorNode,
18463
+ 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,
18464
+ diagnosticName(right),
18465
+ diagnosticName(classWithShadowedPrivateName.name || ("(anonymous)" as __String))
18466
+ );
18467
+ }
18468
+ return undefined;
18469
+ }
18470
+ return prop;
18471
+ }
18472
+ else {
18473
+ classWithShadowedPrivateName = container;
18474
+ }
18475
+ }
18476
+ container = getContainingClass(container);
18477
+ }
18478
+ // If this isn't a case of shadowing, and the lhs has a property with the same
18479
+ // private name description, then there is a privacy violation
18480
+ if (leftType.symbol.members) {
18481
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(leftType.symbol, right.escapedText);
18482
+ const prop = getPropertyOfType(apparentType, symbolTableKey);
18483
+ if (prop) {
18484
+ if (errorNode) {
18485
+ error(right, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_name, symbolToString(prop), typeToString(getDeclaringClass(prop)!));
18486
+ }
18487
+ }
18488
+ }
18489
+ // not found
18490
+ return undefined;
18491
+ }
18492
+
18426
18493
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier | PrivateName) {
18427
18494
let propType: Type;
18428
18495
const leftType = checkNonNullExpression(left);
@@ -18435,7 +18502,7 @@ namespace ts {
18435
18502
return apparentType;
18436
18503
}
18437
18504
const assignmentKind = getAssignmentTargetKind(node);
18438
- const prop = getPropertyOfType(apparentType, right.escapedText);
18505
+ const prop = isPrivateName(right) ? getPropertyForPrivateName(apparentType, leftType, right, /* errorNode */ right) : getPropertyOfType(apparentType, right.escapedText);
18439
18506
if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
18440
18507
markAliasReferenced(parentSymbol, node);
18441
18508
}
@@ -21376,6 +21443,9 @@ namespace ts {
21376
21443
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
21377
21444
return booleanType;
21378
21445
}
21446
+ if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) {
21447
+ error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name);
21448
+ }
21379
21449
const links = getNodeLinks(expr);
21380
21450
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
21381
21451
if (symbol && isReadonlySymbol(symbol)) {
@@ -22529,9 +22599,6 @@ namespace ts {
22529
22599
checkGrammarDecoratorsAndModifiers(node);
22530
22600
22531
22601
checkVariableLikeDeclaration(node);
22532
- if (node.name && isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
22533
- error(node, Diagnostics.Private_names_cannot_be_used_as_parameters);
22534
- }
22535
22602
const func = getContainingFunction(node)!;
22536
22603
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
22537
22604
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
@@ -29210,6 +29277,9 @@ namespace ts {
29210
29277
else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (<ParameterDeclaration>node).dotDotDotToken) {
29211
29278
return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter);
29212
29279
}
29280
+ else if (isNamedDeclaration(node) && (flags & ModifierFlags.AccessibilityModifier) && node.name.kind === SyntaxKind.PrivateName) {
29281
+ return grammarErrorOnNode(node, Diagnostics.Accessibility_modifiers_cannot_be_used_with_private_names);
29282
+ }
29213
29283
if (flags & ModifierFlags.Async) {
29214
29284
return checkGrammarAsyncModifier(node, lastAsync!);
29215
29285
}
@@ -29611,6 +29681,10 @@ namespace ts {
29611
29681
return grammarErrorOnNode(prop.equalsToken!, Diagnostics.can_only_be_used_in_an_object_literal_property_inside_a_destructuring_assignment);
29612
29682
}
29613
29683
29684
+ if (name.kind === SyntaxKind.PrivateName) {
29685
+ return grammarErrorOnNode(name, Diagnostics.Private_names_are_not_allowed_outside_class_bodies);
29686
+ }
29687
+
29614
29688
// Modifiers are never allowed on properties except for 'async' on a method declaration
29615
29689
if (prop.modifiers) {
29616
29690
for (const mod of prop.modifiers!) { // TODO: GH#19955
@@ -30035,10 +30109,6 @@ namespace ts {
30035
30109
checkESModuleMarker(node.name);
30036
30110
}
30037
30111
30038
- if (isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
30039
- return grammarErrorOnNode(node.name, Diagnostics.Private_names_are_not_allowed_in_variable_declarations);
30040
- }
30041
-
30042
30112
const checkLetConstNames = (isLet(node) || isVarConst(node));
30043
30113
30044
30114
// 1. LexicalDeclaration : LetOrConst BindingList ;
0 commit comments