@@ -7896,9 +7896,10 @@ namespace ts {
7896
7896
if (symbol.valueDeclaration && isBinaryExpression(symbol.valueDeclaration)) {
7897
7897
const links = getSymbolLinks(symbol);
7898
7898
if (links.isConstructorDeclaredProperty === undefined) {
7899
+ links.isConstructorDeclaredProperty = false;
7899
7900
links.isConstructorDeclaredProperty = !!getDeclaringConstructor(symbol) && every(symbol.declarations, declaration =>
7900
7901
isBinaryExpression(declaration) &&
7901
- getAssignmentDeclarationKind (declaration) === AssignmentDeclarationKind.ThisProperty &&
7902
+ isPossiblyAliasedThisProperty (declaration) &&
7902
7903
(declaration.left.kind !== SyntaxKind.ElementAccessExpression || isStringOrNumericLiteralLike((<ElementAccessExpression>declaration.left).argumentExpression)) &&
7903
7904
!getAnnotatedTypeForAssignmentDeclaration(/*declaredType*/ undefined, declaration, symbol, declaration));
7904
7905
}
@@ -7975,7 +7976,7 @@ namespace ts {
7975
7976
const kind = isAccessExpression(expression)
7976
7977
? getAssignmentDeclarationPropertyAccessKind(expression)
7977
7978
: getAssignmentDeclarationKind(expression);
7978
- if (kind === AssignmentDeclarationKind.ThisProperty) {
7979
+ if (kind === AssignmentDeclarationKind.ThisProperty || isBinaryExpression(expression) && isPossiblyAliasedThisProperty(expression, kind) ) {
7979
7980
if (isDeclarationInConstructor(expression)) {
7980
7981
definedInConstructor = true;
7981
7982
}
@@ -9637,7 +9638,7 @@ namespace ts {
9637
9638
for (const member of decls) {
9638
9639
const assignmentKind = getAssignmentDeclarationKind(member as BinaryExpression | CallExpression);
9639
9640
const isInstanceMember = assignmentKind === AssignmentDeclarationKind.PrototypeProperty
9640
- || assignmentKind === AssignmentDeclarationKind.ThisProperty
9641
+ || isBinaryExpression(member) && isPossiblyAliasedThisProperty(member, assignmentKind)
9641
9642
|| assignmentKind === AssignmentDeclarationKind.ObjectDefinePrototypeProperty
9642
9643
|| assignmentKind === AssignmentDeclarationKind.Prototype; // A straight `Prototype` assignment probably can never have a computed name
9643
9644
if (isStatic === !isInstanceMember && hasLateBindableName(member)) {
@@ -23125,14 +23126,7 @@ namespace ts {
23125
23126
case SyntaxKind.AmpersandAmpersandEqualsToken:
23126
23127
case SyntaxKind.BarBarEqualsToken:
23127
23128
case SyntaxKind.QuestionQuestionEqualsToken:
23128
- if (node !== right) {
23129
- return undefined;
23130
- }
23131
- const contextSensitive = getIsContextSensitiveAssignmentOrContextType(binaryExpression);
23132
- if (!contextSensitive) {
23133
- return undefined;
23134
- }
23135
- return contextSensitive === true ? getTypeOfExpression(left) : contextSensitive;
23129
+ return node === right ? getContextualTypeForAssignmentDeclaration(binaryExpression) : undefined;
23136
23130
case SyntaxKind.BarBarToken:
23137
23131
case SyntaxKind.QuestionQuestionToken:
23138
23132
// When an || expression has a contextual type, the operands are contextually typed by that type, except
@@ -23153,24 +23147,27 @@ namespace ts {
23153
23147
23154
23148
// In an assignment expression, the right operand is contextually typed by the type of the left operand.
23155
23149
// Don't do this for assignment declarations unless there is a type tag on the assignment, to avoid circularity from checking the right operand.
23156
- function getIsContextSensitiveAssignmentOrContextType (binaryExpression: BinaryExpression): boolean | Type {
23150
+ function getContextualTypeForAssignmentDeclaration (binaryExpression: BinaryExpression): Type | undefined {
23157
23151
const kind = getAssignmentDeclarationKind(binaryExpression);
23158
23152
switch (kind) {
23159
23153
case AssignmentDeclarationKind.None:
23160
- return true ;
23154
+ return getTypeOfExpression(binaryExpression.left) ;
23161
23155
case AssignmentDeclarationKind.Property:
23162
23156
case AssignmentDeclarationKind.ExportsProperty:
23163
23157
case AssignmentDeclarationKind.Prototype:
23164
23158
case AssignmentDeclarationKind.PrototypeProperty:
23159
+ if (isPossiblyAliasedThisProperty(binaryExpression, kind)) {
23160
+ return getContextualTypeForThisPropertyAssignment(binaryExpression, kind);
23161
+ }
23165
23162
// If `binaryExpression.left` was assigned a symbol, then this is a new declaration; otherwise it is an assignment to an existing declaration.
23166
23163
// See `bindStaticPropertyAssignment` in `binder.ts`.
23167
- if (!binaryExpression.left.symbol) {
23168
- return true ;
23164
+ else if (!binaryExpression.left.symbol) {
23165
+ return getTypeOfExpression(binaryExpression.left) ;
23169
23166
}
23170
23167
else {
23171
23168
const decl = binaryExpression.left.symbol.valueDeclaration;
23172
23169
if (!decl) {
23173
- return false ;
23170
+ return undefined ;
23174
23171
}
23175
23172
const lhs = cast(binaryExpression.left, isAccessExpression);
23176
23173
const overallAnnotation = getEffectiveTypeAnnotationNode(decl);
@@ -23185,35 +23182,17 @@ namespace ts {
23185
23182
if (annotated) {
23186
23183
const nameStr = getElementOrPropertyAccessName(lhs);
23187
23184
if (nameStr !== undefined) {
23188
- const type = getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), nameStr);
23189
- return type || false;
23185
+ return getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), nameStr);
23190
23186
}
23191
23187
}
23192
- return false ;
23188
+ return undefined ;
23193
23189
}
23194
23190
}
23195
- return ! isInJSFile(decl);
23191
+ return isInJSFile(decl) ? undefined : getTypeOfExpression(binaryExpression.left );
23196
23192
}
23197
23193
case AssignmentDeclarationKind.ModuleExports:
23198
23194
case AssignmentDeclarationKind.ThisProperty:
23199
- if (!binaryExpression.symbol) return true;
23200
- if (binaryExpression.symbol.valueDeclaration) {
23201
- const annotated = getEffectiveTypeAnnotationNode(binaryExpression.symbol.valueDeclaration);
23202
- if (annotated) {
23203
- const type = getTypeFromTypeNode(annotated);
23204
- if (type) {
23205
- return type;
23206
- }
23207
- }
23208
- }
23209
- if (kind === AssignmentDeclarationKind.ModuleExports) return false;
23210
- const thisAccess = cast(binaryExpression.left, isAccessExpression);
23211
- if (!isObjectLiteralMethod(getThisContainer(thisAccess.expression, /*includeArrowFunctions*/ false))) {
23212
- return false;
23213
- }
23214
- const thisType = checkThisExpression(thisAccess.expression);
23215
- const nameStr = getElementOrPropertyAccessName(thisAccess);
23216
- return nameStr !== undefined && thisType && getTypeOfPropertyOfContextualType(thisType, nameStr) || false;
23195
+ return getContextualTypeForThisPropertyAssignment(binaryExpression, kind);
23217
23196
case AssignmentDeclarationKind.ObjectDefinePropertyValue:
23218
23197
case AssignmentDeclarationKind.ObjectDefinePropertyExports:
23219
23198
case AssignmentDeclarationKind.ObjectDefinePrototypeProperty:
@@ -23223,6 +23202,40 @@ namespace ts {
23223
23202
}
23224
23203
}
23225
23204
23205
+ function isPossiblyAliasedThisProperty(declaration: BinaryExpression, kind = getAssignmentDeclarationKind(declaration)) {
23206
+ if (kind === AssignmentDeclarationKind.ThisProperty) {
23207
+ return true;
23208
+ }
23209
+ if (!isInJSFile(declaration) || kind !== AssignmentDeclarationKind.Property || !isIdentifier((declaration.left as AccessExpression).expression)) {
23210
+ return false;
23211
+ }
23212
+ const name = ((declaration.left as AccessExpression).expression as Identifier).escapedText;
23213
+ const symbol = resolveName(declaration.left, name, SymbolFlags.Value, undefined, undefined, /*isUse*/ true, /*excludeGlobals*/ true);
23214
+ return isThisInitializedDeclaration(symbol?.valueDeclaration);
23215
+ }
23216
+
23217
+ function getContextualTypeForThisPropertyAssignment(binaryExpression: BinaryExpression, kind: AssignmentDeclarationKind): Type | undefined {
23218
+ if (!binaryExpression.symbol) return getTypeOfExpression(binaryExpression.left);
23219
+ if (binaryExpression.symbol.valueDeclaration) {
23220
+ const annotated = getEffectiveTypeAnnotationNode(binaryExpression.symbol.valueDeclaration);
23221
+ if (annotated) {
23222
+ const type = getTypeFromTypeNode(annotated);
23223
+ if (type) {
23224
+ return type;
23225
+ }
23226
+ }
23227
+ }
23228
+ if (kind === AssignmentDeclarationKind.ModuleExports) return undefined;
23229
+ const thisAccess = cast(binaryExpression.left, isAccessExpression);
23230
+ if (!isObjectLiteralMethod(getThisContainer(thisAccess.expression, /*includeArrowFunctions*/ false))) {
23231
+ return undefined;
23232
+ }
23233
+ const thisType = checkThisExpression(thisAccess.expression);
23234
+ const nameStr = getElementOrPropertyAccessName(thisAccess);
23235
+ return nameStr !== undefined && getTypeOfPropertyOfContextualType(thisType, nameStr) || undefined;
23236
+
23237
+ }
23238
+
23226
23239
function isCircularMappedProperty(symbol: Symbol) {
23227
23240
return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(<MappedSymbol>symbol).type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0);
23228
23241
}
@@ -25058,7 +25071,8 @@ namespace ts {
25058
25071
}
25059
25072
25060
25073
function isThisPropertyAccessInConstructor(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol) {
25061
- return isThisProperty(node) && (isAutoTypedProperty(prop) || isConstructorDeclaredProperty(prop)) && getThisContainer(node, /*includeArrowFunctions*/ true) === getDeclaringConstructor(prop);
25074
+ return (isConstructorDeclaredProperty(prop) || isThisProperty(node) && isAutoTypedProperty(prop))
25075
+ && getThisContainer(node, /*includeArrowFunctions*/ true) === getDeclaringConstructor(prop);
25062
25076
}
25063
25077
25064
25078
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, leftType: Type, right: Identifier | PrivateIdentifier) {
0 commit comments