diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 310325d97d2..fbe192c5629 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13258,13 +13258,25 @@ namespace ts { const binaryExpression = node.parent; const operator = binaryExpression.operatorToken.kind; if (isAssignmentOperator(operator)) { - // Don't do this for special property assignments to avoid circularity - if (getSpecialPropertyAssignmentKind(binaryExpression) !== SpecialPropertyAssignmentKind.None) { - return undefined; - } - - // In an assignment expression, the right operand is contextually typed by the type of the left operand. if (node === binaryExpression.right) { + // Don't do this for special property assignments to avoid circularity + switch (getSpecialPropertyAssignmentKind(binaryExpression)) { + case SpecialPropertyAssignmentKind.None: + break; + case SpecialPropertyAssignmentKind.Property: + // If `binaryExpression.left` was assigned a symbol, then this is a new declaration; otherwise it is an assignment to an existing declaration. + // See `bindStaticPropertyAssignment` in `binder.ts`. + if (!binaryExpression.left.symbol) { + break; + } + // falls through + case SpecialPropertyAssignmentKind.ExportsProperty: + case SpecialPropertyAssignmentKind.ModuleExports: + case SpecialPropertyAssignmentKind.PrototypeProperty: + case SpecialPropertyAssignmentKind.ThisProperty: + return undefined; + } + // In an assignment expression, the right operand is contextually typed by the type of the left operand. return getTypeOfExpression(binaryExpression.left); } } diff --git a/tests/cases/fourslash/codeFixUndeclaredAcrossFiles1.ts b/tests/cases/fourslash/codeFixUndeclaredAcrossFiles1.ts index 435b78ba3fa..a946b60f173 100644 --- a/tests/cases/fourslash/codeFixUndeclaredAcrossFiles1.ts +++ b/tests/cases/fourslash/codeFixUndeclaredAcrossFiles1.ts @@ -23,7 +23,7 @@ verify.getAndApplyCodeFix(/*errorCode*/undefined, 0); verify.getAndApplyCodeFix(/*errorCode*/undefined, 0); verify.rangeIs(` - y: { [x: string]: any; }; + y: {}; m1(): any { throw new Error("Method not implemented."); } diff --git a/tests/cases/fourslash/completionsJsPropertyAssignment.ts b/tests/cases/fourslash/completionsJsPropertyAssignment.ts new file mode 100644 index 00000000000..c7e8a9ad268 --- /dev/null +++ b/tests/cases/fourslash/completionsJsPropertyAssignment.ts @@ -0,0 +1,10 @@ +/// + +// @allowJs: true + +// @Filename: /a.js +/////** @type {{ p: "x" | "y" }} */ +////const x = { p: "x" }; +////x.p = "/**/"; + +verify.completionsAt("", ["x", "y"]);