@@ -7896,9 +7896,10 @@ namespace ts {
78967896 if (symbol.valueDeclaration && isBinaryExpression(symbol.valueDeclaration)) {
78977897 const links = getSymbolLinks(symbol);
78987898 if (links.isConstructorDeclaredProperty === undefined) {
7899+ links.isConstructorDeclaredProperty = false;
78997900 links.isConstructorDeclaredProperty = !!getDeclaringConstructor(symbol) && every(symbol.declarations, declaration =>
79007901 isBinaryExpression(declaration) &&
7901- getAssignmentDeclarationKind (declaration) === AssignmentDeclarationKind.ThisProperty &&
7902+ isPossiblyAliasedThisProperty (declaration) &&
79027903 (declaration.left.kind !== SyntaxKind.ElementAccessExpression || isStringOrNumericLiteralLike((<ElementAccessExpression>declaration.left).argumentExpression)) &&
79037904 !getAnnotatedTypeForAssignmentDeclaration(/*declaredType*/ undefined, declaration, symbol, declaration));
79047905 }
@@ -7975,7 +7976,7 @@ namespace ts {
79757976 const kind = isAccessExpression(expression)
79767977 ? getAssignmentDeclarationPropertyAccessKind(expression)
79777978 : getAssignmentDeclarationKind(expression);
7978- if (kind === AssignmentDeclarationKind.ThisProperty) {
7979+ if (kind === AssignmentDeclarationKind.ThisProperty || isBinaryExpression(expression) && isPossiblyAliasedThisProperty(expression, kind) ) {
79797980 if (isDeclarationInConstructor(expression)) {
79807981 definedInConstructor = true;
79817982 }
@@ -9637,7 +9638,7 @@ namespace ts {
96379638 for (const member of decls) {
96389639 const assignmentKind = getAssignmentDeclarationKind(member as BinaryExpression | CallExpression);
96399640 const isInstanceMember = assignmentKind === AssignmentDeclarationKind.PrototypeProperty
9640- || assignmentKind === AssignmentDeclarationKind.ThisProperty
9641+ || isBinaryExpression(member) && isPossiblyAliasedThisProperty(member, assignmentKind)
96419642 || assignmentKind === AssignmentDeclarationKind.ObjectDefinePrototypeProperty
96429643 || assignmentKind === AssignmentDeclarationKind.Prototype; // A straight `Prototype` assignment probably can never have a computed name
96439644 if (isStatic === !isInstanceMember && hasLateBindableName(member)) {
@@ -23125,14 +23126,7 @@ namespace ts {
2312523126 case SyntaxKind.AmpersandAmpersandEqualsToken:
2312623127 case SyntaxKind.BarBarEqualsToken:
2312723128 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;
2313623130 case SyntaxKind.BarBarToken:
2313723131 case SyntaxKind.QuestionQuestionToken:
2313823132 // When an || expression has a contextual type, the operands are contextually typed by that type, except
@@ -23153,24 +23147,27 @@ namespace ts {
2315323147
2315423148 // In an assignment expression, the right operand is contextually typed by the type of the left operand.
2315523149 // 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 {
2315723151 const kind = getAssignmentDeclarationKind(binaryExpression);
2315823152 switch (kind) {
2315923153 case AssignmentDeclarationKind.None:
23160- return true ;
23154+ return getTypeOfExpression(binaryExpression.left) ;
2316123155 case AssignmentDeclarationKind.Property:
2316223156 case AssignmentDeclarationKind.ExportsProperty:
2316323157 case AssignmentDeclarationKind.Prototype:
2316423158 case AssignmentDeclarationKind.PrototypeProperty:
23159+ if (isPossiblyAliasedThisProperty(binaryExpression, kind)) {
23160+ return getContextualTypeForThisPropertyAssignment(binaryExpression, kind);
23161+ }
2316523162 // If `binaryExpression.left` was assigned a symbol, then this is a new declaration; otherwise it is an assignment to an existing declaration.
2316623163 // See `bindStaticPropertyAssignment` in `binder.ts`.
23167- if (!binaryExpression.left.symbol) {
23168- return true ;
23164+ else if (!binaryExpression.left.symbol) {
23165+ return getTypeOfExpression(binaryExpression.left) ;
2316923166 }
2317023167 else {
2317123168 const decl = binaryExpression.left.symbol.valueDeclaration;
2317223169 if (!decl) {
23173- return false ;
23170+ return undefined ;
2317423171 }
2317523172 const lhs = cast(binaryExpression.left, isAccessExpression);
2317623173 const overallAnnotation = getEffectiveTypeAnnotationNode(decl);
@@ -23185,35 +23182,17 @@ namespace ts {
2318523182 if (annotated) {
2318623183 const nameStr = getElementOrPropertyAccessName(lhs);
2318723184 if (nameStr !== undefined) {
23188- const type = getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), nameStr);
23189- return type || false;
23185+ return getTypeOfPropertyOfContextualType(getTypeFromTypeNode(annotated), nameStr);
2319023186 }
2319123187 }
23192- return false ;
23188+ return undefined ;
2319323189 }
2319423190 }
23195- return ! isInJSFile(decl);
23191+ return isInJSFile(decl) ? undefined : getTypeOfExpression(binaryExpression.left );
2319623192 }
2319723193 case AssignmentDeclarationKind.ModuleExports:
2319823194 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);
2321723196 case AssignmentDeclarationKind.ObjectDefinePropertyValue:
2321823197 case AssignmentDeclarationKind.ObjectDefinePropertyExports:
2321923198 case AssignmentDeclarationKind.ObjectDefinePrototypeProperty:
@@ -23223,6 +23202,40 @@ namespace ts {
2322323202 }
2322423203 }
2322523204
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+
2322623239 function isCircularMappedProperty(symbol: Symbol) {
2322723240 return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(<MappedSymbol>symbol).type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0);
2322823241 }
@@ -25058,7 +25071,8 @@ namespace ts {
2505825071 }
2505925072
2506025073 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);
2506225076 }
2506325077
2506425078 function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, leftType: Type, right: Identifier | PrivateIdentifier) {
0 commit comments