From 6c205330a1079c96a473254f6b83da4a5020acd7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 30 Oct 2016 18:08:43 -0700 Subject: [PATCH] Improved error messages for invalid assignments to properties --- src/compiler/checker.ts | 15 ++++++++++++--- src/compiler/utilities.ts | 6 +++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5e23f56b947..bf3a4b94d0c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11459,16 +11459,25 @@ namespace ts { } const propType = getTypeOfSymbol(prop); + const assignmentKind = getAssignmentTargetKind(node); + + if (assignmentKind) { + if (isReferenceToReadonlyEntity(node, prop) || isReferenceThroughNamespaceImport(node)) { + error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, right.text); + return unknownType; + } + } // Only compute control flow type if this is a property access expression that isn't an // assignment target, and the referenced property was declared as a variable, property, // accessor, or optional method. - if (node.kind !== SyntaxKind.PropertyAccessExpression || isAssignmentTarget(node) || + if (node.kind !== SyntaxKind.PropertyAccessExpression || assignmentKind === AssignmentKind.Definite || !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) { return propType; } - return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined); + const flowType = getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined); + return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; } function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean { @@ -13515,7 +13524,7 @@ namespace ts { error(expr, invalidReferenceMessage); return false; } - if (node.kind === SyntaxKind.Identifier) { + if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) { return true; } // Because we get the symbol from the resolvedSymbol property, it might be of kind diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f9fe30b4e53..e2e401cfae4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1649,8 +1649,12 @@ namespace ts { case SyntaxKind.SpreadElementExpression: node = parent; break; - case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: + if ((parent).name !== node) { + return AssignmentKind.None; + } + // Fall through + case SyntaxKind.PropertyAssignment: node = parent.parent; break; default: