@@ -11964,7 +11964,7 @@ namespace ts {
1196411964 if (prop) {
1196511965 if (accessExpression) {
1196611966 markPropertyAsReferenced(prop, accessExpression, /*isThisAccess*/ accessExpression.expression.kind === SyntaxKind.ThisKeyword);
11967- if (isAssignmentTarget (accessExpression) && (isReferenceToReadonlyEntity(accessExpression , prop) || isReferenceThroughNamespaceImport (accessExpression))) {
11967+ if (isAssignmentToReadonlyEntity (accessExpression, prop, getAssignmentTargetKind (accessExpression))) {
1196811968 error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop));
1196911969 return undefined;
1197011970 }
@@ -23046,11 +23046,9 @@ namespace ts {
2304623046 markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
2304723047 getNodeLinks(node).resolvedSymbol = prop;
2304823048 checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop);
23049- if (assignmentKind) {
23050- if (isReferenceToReadonlyEntity(<Expression>node, prop) || isReferenceThroughNamespaceImport(<Expression>node)) {
23051- error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
23052- return errorType;
23053- }
23049+ if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
23050+ error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
23051+ return errorType;
2305423052 }
2305523053 propType = getConstraintForLocation(getTypeOfSymbol(prop), node);
2305623054 }
@@ -26332,29 +26330,39 @@ namespace ts {
2633226330 );
2633326331 }
2633426332
26335- function isReferenceToReadonlyEntity(expr: Expression, symbol: Symbol): boolean {
26333+ function isAssignmentToReadonlyEntity(expr: Expression, symbol: Symbol, assignmentKind: AssignmentKind) {
26334+ if (assignmentKind === AssignmentKind.None) {
26335+ // no assigment means it doesn't matter whether the entity is readonly
26336+ return false;
26337+ }
2633626338 if (isReadonlySymbol(symbol)) {
2633726339 // Allow assignments to readonly properties within constructors of the same class declaration.
2633826340 if (symbol.flags & SymbolFlags.Property &&
2633926341 (expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
2634026342 (expr as AccessExpression).expression.kind === SyntaxKind.ThisKeyword) {
2634126343 // Look for if this is the constructor for the class that `symbol` is a property of.
26342- const func = getContainingFunction(expr);
26343- if (!(func && func .kind === SyntaxKind.Constructor)) {
26344+ const ctor = getContainingFunction(expr);
26345+ if (!(ctor && ctor .kind === SyntaxKind.Constructor)) {
2634426346 return true;
2634526347 }
26346- // If func.parent is a class and symbol is a (readonly) property of that class, or
26347- // if func is a constructor and symbol is a (readonly) parameter property declared in it,
26348- // then symbol is writeable here.
26349- return !symbol.valueDeclaration || !(func.parent === symbol.valueDeclaration.parent || func === symbol.valueDeclaration.parent);
26348+ if (symbol.valueDeclaration) {
26349+ const isAssignmentDeclaration = isBinaryExpression(symbol.valueDeclaration);
26350+ const isLocalPropertyDeclaration = ctor.parent === symbol.valueDeclaration.parent;
26351+ const isLocalParameterProperty = ctor === symbol.valueDeclaration.parent;
26352+ const isLocalThisPropertyAssignment = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor.parent;
26353+ const isLocalThisPropertyAssignmentConstructorFunction = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor;
26354+ const isWriteableSymbol =
26355+ isLocalPropertyDeclaration
26356+ || isLocalParameterProperty
26357+ || isLocalThisPropertyAssignment
26358+ || isLocalThisPropertyAssignmentConstructorFunction;
26359+ return !isWriteableSymbol;
26360+ }
2635026361 }
2635126362 return true;
2635226363 }
26353- return false;
26354- }
26355-
26356- function isReferenceThroughNamespaceImport(expr: Expression): boolean {
2635726364 if (expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
26365+ // references through namespace import should be readonly
2635826366 const node = skipParentheses((expr as AccessExpression).expression);
2635926367 if (node.kind === SyntaxKind.Identifier) {
2636026368 const symbol = getNodeLinks(node).resolvedSymbol!;
0 commit comments