@@ -10400,25 +10400,44 @@ namespace ts {
10400
10400
return true;
10401
10401
}
10402
10402
10403
- function isReferenceWithinOwnConstructor(expr: Expression, symbol: Symbol): boolean {
10404
- // Allow assignments to readonly properties or methods (but not readonly accessors) within constructors
10405
- // of the same class declaration.
10406
- if ((expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
10407
- (expr as PropertyAccessExpression | ElementAccessExpression).expression.kind === SyntaxKind.ThisKeyword &&
10408
- symbol.flags & (SymbolFlags.Property | SymbolFlags.Method)) {
10409
- const func = getContainingFunction(expr);
10410
- return func && func.kind === SyntaxKind.Constructor && func.parent === symbol.valueDeclaration.parent;
10411
- }
10412
- }
10413
-
10414
10403
function isReadonlySymbol(symbol: Symbol): boolean {
10415
10404
return symbol.flags & SymbolFlags.Property && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Readonly) !== 0;
10416
10405
}
10417
10406
10418
- function isConstantSymbol(symbol: Symbol): boolean {
10419
- return symbol === undefinedSymbol ||
10420
- symbol.flags & SymbolFlags.Variable && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 ||
10421
- symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor);
10407
+ function isReferenceToConstant(expr: Expression, symbol: Symbol): boolean {
10408
+ if (symbol.flags & SymbolFlags.Variable) {
10409
+ // A variable declared with 'const' is considered constant.
10410
+ if (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Const) {
10411
+ return true;
10412
+ }
10413
+ // An exported variable declared in an external module and accessed through a property
10414
+ // or element access is considered constant.
10415
+ if (expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
10416
+ if (symbol.parent && symbol.parent.flags & SymbolFlags.ValueModule) {
10417
+ const declaration = symbol.parent.valueDeclaration;
10418
+ return declaration && (declaration.kind === SyntaxKind.SourceFile ||
10419
+ declaration.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>declaration).name.kind === SyntaxKind.StringLiteral);
10420
+ }
10421
+ }
10422
+ }
10423
+ if (symbol.flags & SymbolFlags.Accessor) {
10424
+ // An get accessor with no corresponding set accessor is considered constant.
10425
+ return !(symbol.flags & SymbolFlags.SetAccessor);
10426
+ }
10427
+ return false;
10428
+ }
10429
+
10430
+ function isReferenceToReadonlyProperty(expr: Expression, symbol: Symbol): boolean {
10431
+ if (isReadonlySymbol(symbol)) {
10432
+ // Allow assignments to readonly properties within constructors of the same class declaration.
10433
+ if ((expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
10434
+ (expr as PropertyAccessExpression | ElementAccessExpression).expression.kind === SyntaxKind.ThisKeyword) {
10435
+ const func = getContainingFunction(expr);
10436
+ return !(func && func.kind === SyntaxKind.Constructor && func.parent === symbol.valueDeclaration.parent);
10437
+ }
10438
+ return true;
10439
+ }
10440
+ return false;
10422
10441
}
10423
10442
10424
10443
function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage, constantVariableMessage: DiagnosticMessage): boolean {
@@ -10435,11 +10454,12 @@ namespace ts {
10435
10454
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
10436
10455
if (symbol) {
10437
10456
if (symbol !== unknownSymbol && symbol !== argumentsSymbol) {
10438
- if (symbol === undefinedSymbol || !(symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Method | SymbolFlags.Accessor))) {
10457
+ if (symbol === undefinedSymbol ||
10458
+ !(symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Method | SymbolFlags.Accessor))) {
10439
10459
error(expr, invalidReferenceMessage);
10440
10460
return false;
10441
10461
}
10442
- if (isConstantSymbol( symbol) || (isReadonlySymbol(symbol) && !isReferenceWithinOwnConstructor(expr , symbol) )) {
10462
+ if (isReferenceToConstant(node, symbol) || isReferenceToReadonlyProperty(node , symbol)) {
10443
10463
error(expr, constantVariableMessage);
10444
10464
return false;
10445
10465
}
0 commit comments