From afb83fcac3a0984f61de6f8acfaee220f5e2779f Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk Date: Mon, 20 Jul 2026 18:55:27 +0300 Subject: [PATCH 1/2] fix(4677): preserve JSDoc for mapped type properties in hover --- .../hoverMappedTypePropertyJSDoc_test.go | 37 ++++++++ internal/ls/hover.go | 2 +- .../hoverMappedTypePropertyJSDoc.baseline | 93 +++++++++++++++++++ ...rtiesWithIdenticalJSDocComments01.baseline | 4 +- 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 internal/fourslash/tests/hoverMappedTypePropertyJSDoc_test.go create mode 100644 testdata/baselines/reference/fourslash/quickInfo/hoverMappedTypePropertyJSDoc.baseline diff --git a/internal/fourslash/tests/hoverMappedTypePropertyJSDoc_test.go b/internal/fourslash/tests/hoverMappedTypePropertyJSDoc_test.go new file mode 100644 index 00000000000..476e6b8a205 --- /dev/null +++ b/internal/fourslash/tests/hoverMappedTypePropertyJSDoc_test.go @@ -0,0 +1,37 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/fourslash" + "github.com/microsoft/typescript-go/internal/testutil" +) + +func TestHoverMappedTypePropertyJSDoc(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = ` +// @filename: a.ts +export declare const A: Readonly<{ + /** + * x prop + */ + readonly X: 200; + + /** + * y prop + */ + readonly Y: 201; +}>; + +A.X/*1*/; + +// @filename: b.ts +import { A } from './a'; + +A.X/*2*/; +` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineHover(t) +} diff --git a/internal/ls/hover.go b/internal/ls/hover.go index 22d2e93982f..0586862dfe4 100644 --- a/internal/ls/hover.go +++ b/internal/ls/hover.go @@ -639,7 +639,7 @@ func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, symbol *ast.Symbol writeTypeClassified(t, container, typeFormatFlags) } } - setDeclaration(symbol.ValueDeclaration) + setDeclaration(core.OrElse(symbol.ValueDeclaration, core.FirstOrNil(symbol.Declarations))) } if flags&ast.SymbolFlagsEnumMember != 0 { writeNewLine() diff --git a/testdata/baselines/reference/fourslash/quickInfo/hoverMappedTypePropertyJSDoc.baseline b/testdata/baselines/reference/fourslash/quickInfo/hoverMappedTypePropertyJSDoc.baseline new file mode 100644 index 00000000000..821ba24356a --- /dev/null +++ b/testdata/baselines/reference/fourslash/quickInfo/hoverMappedTypePropertyJSDoc.baseline @@ -0,0 +1,93 @@ +// === QuickInfo === +=== /a.ts === +// export declare const A: Readonly<{ +// /** +// * x prop +// */ +// readonly X: 200; +// +// /** +// * y prop +// */ +// readonly Y: 201; +// }>; +// +// A.X; +// ^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (property) X: 200 +// | ``` +// | x prop +// | ---------------------------------------------------------------------- +// +=== /b.ts === +// import { A } from './a'; +// +// A.X; +// ^ +// | ---------------------------------------------------------------------- +// | ```typescript +// | (property) X: 200 +// | ``` +// | x prop +// | ---------------------------------------------------------------------- +// + + +[ + { + "marker": { + "Position": 130, + "LSPosition": { + "line": 12, + "character": 3 + }, + "Name": "1", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(property) X: 200\n```\nx prop" + }, + "range": { + "start": { + "line": 12, + "character": 2 + }, + "end": { + "line": 12, + "character": 3 + } + } + } + }, + { + "marker": { + "Position": 29, + "LSPosition": { + "line": 2, + "character": 3 + }, + "Name": "2", + "Data": {} + }, + "item": { + "contents": { + "kind": "markdown", + "value": "```typescript\n(property) X: 200\n```\nx prop" + }, + "range": { + "start": { + "line": 2, + "character": 2 + }, + "end": { + "line": 2, + "character": 3 + } + } + } + } +] \ No newline at end of file diff --git a/testdata/baselines/reference/fourslash/quickInfo/quickInfoOnUnionPropertiesWithIdenticalJSDocComments01.baseline b/testdata/baselines/reference/fourslash/quickInfo/quickInfoOnUnionPropertiesWithIdenticalJSDocComments01.baseline index eb716512b25..40219f5b8db 100644 --- a/testdata/baselines/reference/fourslash/quickInfo/quickInfoOnUnionPropertiesWithIdenticalJSDocComments01.baseline +++ b/testdata/baselines/reference/fourslash/quickInfo/quickInfoOnUnionPropertiesWithIdenticalJSDocComments01.baseline @@ -30,7 +30,7 @@ // | ```typescript // | (property) language?: string | undefined // | ``` -// | +// | A language id, like `typescript`. // | ---------------------------------------------------------------------- [ { @@ -46,7 +46,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```typescript\n(property) language?: string | undefined\n```\n" + "value": "```typescript\n(property) language?: string | undefined\n```\nA language id, like `typescript`." }, "range": { "start": { From 4900e24a30b7222bd91bd142b1d351e0007c06e8 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk Date: Mon, 20 Jul 2026 19:59:29 +0300 Subject: [PATCH 2/2] update failing tests --- internal/fourslash/_scripts/failingTests.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 5254408fde1..45f554a8b84 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -375,7 +375,6 @@ TestQuickInfoJSDocFunctionThis TestQuickInfoJsDocGetterSetterNoCrash1 TestQuickInfoJsdocTypedefMissingType TestQuickInfoJSExport -TestQuickInfoMappedSpreadTypes TestQuickInfoMappedType TestQuickInfoMeaning TestQuickInfoModuleVariables @@ -409,7 +408,6 @@ TestQuickInfoTypeOfThisInStatics TestQuickInfoTypeOnlyNamespaceAndClass TestQuickInfoUnionOfNamespaces TestQuickInfoUntypedModuleImport -TestQuickinfoWrongComment TestRecursiveInternalModuleImport TestRegexDetection TestSelfReferencedExternalModule