diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 02ab562e00091..e14d32ea0cb80 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -44827,6 +44827,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } + function isThisPropertyAndThisTyped(node: PropertyAccessExpression) { + if (node.expression.kind === SyntaxKind.ThisKeyword) { + const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + if (isFunctionLike(container)) { + const containingLiteral = getContainingObjectLiteral(container); + if (containingLiteral) { + const contextualType = getApparentTypeOfContextualType(containingLiteral, /*contextFlags*/ undefined); + const type = contextualType && getThisTypeFromContextualType(contextualType); + return type && !isTypeAny(type); + } + } + } + } + function getSymbolOfNameOrPropertyAccessExpression(name: EntityName | PrivateIdentifier | PropertyAccessExpression | JSDocMemberName): Symbol | undefined { if (isDeclarationName(name)) { return getSymbolOfNode(name.parent); @@ -44836,7 +44850,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { name.parent.kind === SyntaxKind.PropertyAccessExpression && name.parent === (name.parent.parent as BinaryExpression).left) { // Check if this is a special property assignment - if (!isPrivateIdentifier(name) && !isJSDocMemberName(name)) { + if (!isPrivateIdentifier(name) && !isJSDocMemberName(name) && !isThisPropertyAndThisTyped(name.parent as PropertyAccessExpression)) { const specialPropertyAssignmentSymbol = getSpecialPropertyAssignmentSymbolFromEntityName(name); if (specialPropertyAssignmentSymbol) { return specialPropertyAssignmentSymbol; diff --git a/tests/baselines/reference/findAllRefsJsThisPropertyAssignment.baseline.jsonc b/tests/baselines/reference/findAllRefsJsThisPropertyAssignment.baseline.jsonc new file mode 100644 index 0000000000000..e129caedd1322 --- /dev/null +++ b/tests/baselines/reference/findAllRefsJsThisPropertyAssignment.baseline.jsonc @@ -0,0 +1,200 @@ +// === /tests/cases/fourslash/infer.d.ts === +// export declare function infer(o: { m(): void } & ThisType<{ [|x|]: number }>): void; + +// === /tests/cases/fourslash/a.js === +// import { infer } from "./infer"; +// infer({ +// m() { +// this.[|x|] = 1; +// this./*FIND ALL REFS*/[|x|]; +// }, +// }); + +[ + { + "definition": { + "containerKind": "", + "containerName": "", + "fileName": "/tests/cases/fourslash/infer.d.ts", + "kind": "property", + "name": "(property) x: number", + "textSpan": { + "start": 60, + "length": 1 + }, + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "property", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "x", + "kind": "propertyName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "number", + "kind": "keyword" + } + ], + "contextSpan": { + "start": 60, + "length": 9 + } + }, + "references": [ + { + "textSpan": { + "start": 60, + "length": 1 + }, + "fileName": "/tests/cases/fourslash/infer.d.ts", + "contextSpan": { + "start": 60, + "length": 9 + }, + "isWriteAccess": true + }, + { + "textSpan": { + "start": 64, + "length": 1 + }, + "fileName": "/tests/cases/fourslash/a.js", + "contextSpan": { + "start": 59, + "length": 11 + }, + "isWriteAccess": true + }, + { + "textSpan": { + "start": 84, + "length": 1 + }, + "fileName": "/tests/cases/fourslash/a.js", + "isWriteAccess": false + } + ] + } +] + +// === /tests/cases/fourslash/b.js === +// /** +// * @template T +// * @param {{m(): void} & ThisType<{[|x|]: number}>} o +// */ +// function infer(o) {} +// infer({ +// m() { +// this.[|x|] = 2; +// this./*FIND ALL REFS*/[|x|]; +// }, +// }); + +[ + { + "definition": { + "containerKind": "", + "containerName": "", + "fileName": "/tests/cases/fourslash/b.js", + "kind": "property", + "name": "(property) x: number", + "textSpan": { + "start": 54, + "length": 1 + }, + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "property", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "x", + "kind": "propertyName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "number", + "kind": "keyword" + } + ], + "contextSpan": { + "start": 54, + "length": 9 + } + }, + "references": [ + { + "textSpan": { + "start": 54, + "length": 1 + }, + "fileName": "/tests/cases/fourslash/b.js", + "contextSpan": { + "start": 54, + "length": 9 + }, + "isWriteAccess": false + }, + { + "textSpan": { + "start": 125, + "length": 1 + }, + "fileName": "/tests/cases/fourslash/b.js", + "contextSpan": { + "start": 120, + "length": 11 + }, + "isWriteAccess": true + }, + { + "textSpan": { + "start": 145, + "length": 1 + }, + "fileName": "/tests/cases/fourslash/b.js", + "isWriteAccess": false + } + ] + } +] \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefsJsThisPropertyAssignment.ts b/tests/cases/fourslash/findAllRefsJsThisPropertyAssignment.ts new file mode 100644 index 0000000000000..43185587eb858 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsJsThisPropertyAssignment.ts @@ -0,0 +1,31 @@ +/// + +// @allowJs: true +// @noImplicitThis: true + +// @Filename: infer.d.ts +//// export declare function infer(o: { m(): void } & ThisType<{ x: number }>): void; + +// @Filename: a.js +//// import { infer } from "./infer"; +//// infer({ +//// m() { +//// this.x = 1; +//// this./*1*/x; +//// }, +//// }); + +// @Filename: b.js +//// /** +//// * @template T +//// * @param {{m(): void} & ThisType<{x: number}>} o +//// */ +//// function infer(o) {} +//// infer({ +//// m() { +//// this.x = 2; +//// this./*2*/x; +//// }, +//// }); + +verify.baselineFindAllReferences("1", "2");