@@ -27727,11 +27727,8 @@ func (c *Checker) getContextualTypeForBinaryOperand(node *ast.Node, contextFlags
27727
27727
case ast.KindEqualsToken, ast.KindAmpersandAmpersandEqualsToken, ast.KindBarBarEqualsToken, ast.KindQuestionQuestionEqualsToken:
27728
27728
// In an assignment expression, the right operand is contextually typed by the type of the left operand
27729
27729
// unless it's an assignment declaration.
27730
- if node == binary.Right && !c.isReferenceToModuleExports(binary.Left) {
27731
- if binary.Symbol != nil {
27732
- return c.getContextualTypeForAssignmentDeclaration(node.Parent)
27733
- }
27734
- return c.getTypeOfExpression(binary.Left)
27730
+ if node == binary.Right {
27731
+ return c.getContextualTypeForAssignmentExpression(binary)
27735
27732
}
27736
27733
case ast.KindBarBarToken, ast.KindQuestionQuestionToken:
27737
27734
// When an || expression has a contextual type, the operands are contextually typed by that type, except
@@ -27752,78 +27749,73 @@ func (c *Checker) getContextualTypeForBinaryOperand(node *ast.Node, contextFlags
27752
27749
return nil
27753
27750
}
27754
27751
27755
- func (c *Checker) getContextualTypeForAssignmentDeclaration(node *ast.Node) *Type {
27756
- // Node is the left operand of an assignment declaration (a binary expression with a symbol assigned by the
27757
- // binder) of the form 'F.id = expr' or 'F[xxx] = expr'. If 'F' is declared as a variable with a type annotation,
27758
- // we can obtain a contextual type from the annotated type without triggering a circularity. Otherwise, the
27759
- // assignment declaration has no contextual type.
27760
- left := node.AsBinaryExpression().Left
27761
- expr := left.Expression()
27762
- switch expr.Kind {
27763
- case ast.KindThisKeyword:
27764
- var symbol *ast.Symbol
27765
- if ast.IsPropertyAccessExpression(left) {
27766
- name := left.Name()
27767
- thisType := c.getTypeOfExpression(expr)
27768
- if ast.IsPrivateIdentifier(name) {
27769
- symbol = c.getPropertyOfType(thisType, binder.GetSymbolNameForPrivateIdentifier(thisType.symbol, name.Text()))
27770
- } else {
27771
- symbol = c.getPropertyOfType(thisType, name.Text())
27772
- }
27773
- } else {
27774
- propType := c.checkExpressionCached(left.AsElementAccessExpression().ArgumentExpression)
27775
- if isTypeUsableAsPropertyName(propType) {
27776
- symbol = c.getPropertyOfType(c.getTypeOfExpression(expr), getPropertyNameFromType(propType))
27777
- }
27778
- }
27779
- if symbol != nil {
27780
- d := symbol.ValueDeclaration
27781
- if d != nil && (ast.IsPropertyDeclaration(d) || ast.IsPropertySignatureDeclaration(d)) && d.Type() == nil && d.Initializer() == nil {
27752
+ func (c *Checker) getContextualTypeForAssignmentExpression(binary *ast.BinaryExpression) *Type {
27753
+ left := binary.Left
27754
+ if ast.IsAccessExpression(left) {
27755
+ expr := left.Expression()
27756
+ switch expr.Kind {
27757
+ case ast.KindIdentifier:
27758
+ if symbol := c.getExportSymbolOfValueSymbolIfExported(c.getResolvedSymbol(expr)); symbol.Flags&ast.SymbolFlagsModuleExports != 0 {
27759
+ // No contextual type for an expression of the form 'module.exports = expr'.
27782
27760
return nil
27783
27761
}
27784
- }
27785
- symbol = node.Symbol()
27786
- if symbol != nil && symbol.ValueDeclaration != nil && symbol.ValueDeclaration.Type() == nil {
27787
- if !ast.IsObjectLiteralMethod(c.getThisContainer(expr, false, false)) {
27762
+ if binary.Symbol != nil {
27763
+ // We have an assignment declaration (a binary expression with a symbol assigned by the binder) of the form
27764
+ // 'F.id = expr' or 'F[xxx] = expr'. If 'F' is declared as a variable with a type annotation, we can obtain a
27765
+ // contextual type from the annotated type without triggering a circularity. Otherwise, the assignment
27766
+ // declaration has no contextual type.
27767
+ if symbol := c.getExportSymbolOfValueSymbolIfExported(c.getResolvedSymbol(expr)); symbol.ValueDeclaration != nil && ast.IsVariableDeclaration(symbol.ValueDeclaration) {
27768
+ if typeNode := symbol.ValueDeclaration.Type(); typeNode != nil {
27769
+ if ast.IsPropertyAccessExpression(left) {
27770
+ return c.getTypeOfPropertyOfContextualType(c.getTypeFromTypeNode(typeNode), left.Name().Text())
27771
+ }
27772
+ nameType := c.checkExpressionCached(left.AsElementAccessExpression().ArgumentExpression)
27773
+ if isTypeUsableAsPropertyName(nameType) {
27774
+ return c.getTypeOfPropertyOfContextualTypeEx(c.getTypeFromTypeNode(typeNode), getPropertyNameFromType(nameType), nameType)
27775
+ }
27776
+ }
27777
+ }
27788
27778
return nil
27789
27779
}
27790
- // and now for one single case of object literal methods
27791
- name := ast.GetElementOrPropertyAccessName(left)
27792
- if name == nil {
27793
- return nil
27780
+ case ast.KindThisKeyword:
27781
+ var symbol *ast.Symbol
27782
+ if ast.IsPropertyAccessExpression(left) {
27783
+ name := left.Name()
27784
+ thisType := c.getTypeOfExpression(expr)
27785
+ if ast.IsPrivateIdentifier(name) {
27786
+ symbol = c.getPropertyOfType(thisType, binder.GetSymbolNameForPrivateIdentifier(thisType.symbol, name.Text()))
27787
+ } else {
27788
+ symbol = c.getPropertyOfType(thisType, name.Text())
27789
+ }
27794
27790
} else {
27795
- // !!! contextual typing for `this` in object literals
27796
- return nil
27791
+ propType := c.checkExpressionCached(left.AsElementAccessExpression().ArgumentExpression)
27792
+ if isTypeUsableAsPropertyName(propType) {
27793
+ symbol = c.getPropertyOfType(c.getTypeOfExpression(expr), getPropertyNameFromType(propType))
27794
+ }
27797
27795
}
27798
- }
27799
- return c.getTypeOfExpression(left)
27800
- case ast.KindIdentifier:
27801
- symbol := c.getExportSymbolOfValueSymbolIfExported(c.getResolvedSymbol(expr))
27802
- if symbol.ValueDeclaration != nil && ast.IsVariableDeclaration(symbol.ValueDeclaration) {
27803
- if typeNode := symbol.ValueDeclaration.Type(); typeNode != nil {
27804
- if ast.IsPropertyAccessExpression(left) {
27805
- return c.getTypeOfPropertyOfContextualType(c.getTypeFromTypeNode(typeNode), left.Name().Text())
27796
+ if symbol != nil {
27797
+ if d := symbol.ValueDeclaration; d != nil && (ast.IsPropertyDeclaration(d) || ast.IsPropertySignatureDeclaration(d)) && d.Type() == nil && d.Initializer() == nil {
27798
+ // No contextual type for 'this.xxx = expr', where xxx is declared as a property with no type annotation or initializer.
27799
+ return nil
27800
+ }
27801
+ }
27802
+ if binary.Symbol != nil && binary.Symbol.ValueDeclaration != nil && binary.Symbol.ValueDeclaration.Type() == nil {
27803
+ // We have an assignment declaration 'this.xxx = expr' with no (synthetic) type annotation
27804
+ if !ast.IsObjectLiteralMethod(c.getThisContainer(expr, false, false)) {
27805
+ return nil
27806
27806
}
27807
- nameType := c.checkExpressionCached(left.AsElementAccessExpression().ArgumentExpression)
27808
- if isTypeUsableAsPropertyName(nameType) {
27809
- return c.getTypeOfPropertyOfContextualTypeEx(c.getTypeFromTypeNode(typeNode), getPropertyNameFromType(nameType), nameType)
27807
+ // and now for one single case of object literal methods
27808
+ name := ast.GetElementOrPropertyAccessName(left)
27809
+ if name == nil {
27810
+ return nil
27811
+ } else {
27812
+ // !!! contextual typing for `this` in object literals
27813
+ return nil
27810
27814
}
27811
27815
}
27812
27816
}
27813
27817
}
27814
- return nil
27815
- }
27816
-
27817
- func (c *Checker) isReferenceToModuleExports(node *ast.Node) bool {
27818
- if ast.IsAccessExpression(node) {
27819
- expr := node.Expression()
27820
- if ast.IsIdentifier(expr) {
27821
- // Node is the left operand of an assignment expression of the form 'module.exports = expr'.
27822
- symbol := c.getExportSymbolOfValueSymbolIfExported(c.getResolvedSymbol(expr))
27823
- return symbol.Flags&ast.SymbolFlagsModuleExports != 0
27824
- }
27825
- }
27826
- return false
27818
+ return c.getTypeOfExpression(left)
27827
27819
}
27828
27820
27829
27821
func (c *Checker) getContextualTypeForObjectLiteralElement(element *ast.Node, contextFlags ContextFlags) *Type {
0 commit comments