Skip to content

support quick info and go to definition on mapped keys#3264

Open
Zzzen wants to merge 1 commit intomicrosoft:mainfrom
Zzzen:quick-info-on-remapped-props
Open

support quick info and go to definition on mapped keys#3264
Zzzen wants to merge 1 commit intomicrosoft:mainfrom
Zzzen:quick-info-on-remapped-props

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds language service support for Quick Info (hover) and Go to Definition on mapped type properties, including cases where keys are remapped (e.g. via as), aligning behavior with upstream TypeScript fixes for the linked issues.

Changes:

  • Attach and surface JSDoc (notably @inheritDoc) on MappedTypeNode so hover can show documentation for remapped mapped properties.
  • Improve go-to-definition for mapped properties by falling back to the mapped symbol’s syntheticOrigin declarations when the mapped property has no direct declarations.
  • Add fourslash coverage + reference baselines for hover and go-to-definition on mapped keys.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/parser/utilities.go Includes KindMappedType in JSDoc comment range collection so mapped types can have lazily-parsed JSDoc in TS/TSX.
internal/parser/parser.go Records preceding JSDoc info when parsing mapped types and attaches it via withJSDoc.
internal/checker/checker.go Sets prop.Parent for mapped properties to the mapped type symbol to enable doc lookup via parent declarations.
internal/checker/services.go Exposes GetMappedSyntheticOrigin helper for LS to navigate mapped symbols back to their source property symbol.
internal/ls/hover.go Synthesizes hover documentation for mapped properties (when declaration is nil) using mapped type + synthetic origin declarations when @inheritDoc is present.
internal/ls/definition.go Adds go-to-definition fallback to synthetic origin declarations for mapped properties with no declarations.
internal/fourslash/tests/quickInfoMappedType2_test.go Adds/updates quick info fourslash coverage for mapped type @inheritDoc hover.
internal/fourslash/tests/quickInfoMappedType3_test.go Adds hover baseline test for mapped type remapped keys showing inherited doc text.
internal/fourslash/tests/quickInfoMappedType4_test.go Adds a quick info regression test for a different @inheritDoc placement scenario.
internal/fourslash/tests/goToDefinitionMappedType2_test.go Adds go-to-definition fourslash test for mapped keys with remapping.
internal/fourslash/tests/goToDefinitionMappedType3_test.go Adds go-to-definition fourslash test for mapped keys transformed with a suffix.
testdata/baselines/reference/fourslash/quickInfo/quickInfoMappedType3.baseline New reference baseline for hover output on mapped properties.
testdata/baselines/reference/fourslash/goToDefinition/goToDefinitionMappedType2.baseline.jsonc New reference baseline for go-to-definition on remapped mapped keys.
testdata/baselines/reference/fourslash/goToDefinition/goToDefinitionMappedType3.baseline.jsonc New reference baseline for go-to-definition on suffix-transformed keys.
Comments suppressed due to low confidence (1)

internal/fourslash/tests/quickInfoMappedType3_test.go:54

  • Same as above: this comment says hover docs are not displayed, but the updated baseline indicates documentation is shown. Please update the marker comment to match expected behavior.
// ❌ When hovering here, the documentation is NOT displayed.
me./*4*/getName();`

Comment on lines +45 to +53
// ❌ When hovering here, the documentation is NOT displayed.
/*1*/getName: () => "Jake Carter",
// ❌ When hovering here, the documentation is NOT displayed.
/*2*/getAge: () => 35,
// ❌ When hovering here, the documentation is NOT displayed.
/*3*/getLocation: () => "United States",
};

// ❌ When hovering here, the documentation is NOT displayed.
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The embedded test source still says hover documentation is not displayed for the mapped properties/call sites, but the baseline now shows documentation coming from the mapped type's @inheritdoc. Please update these ❌ comments to match the new expected behavior to avoid confusing future test readers.

This issue also appears on line 53 of the same file.

Suggested change
// When hovering here, the documentation is NOT displayed.
/*1*/getName: () => "Jake Carter",
// When hovering here, the documentation is NOT displayed.
/*2*/getAge: () => 35,
// When hovering here, the documentation is NOT displayed.
/*3*/getLocation: () => "United States",
};
// When hovering here, the documentation is NOT displayed.
// When hovering here, the documentation is displayed, as it should.
/*1*/getName: () => "Jake Carter",
// When hovering here, the documentation is displayed, as it should.
/*2*/getAge: () => 35,
// When hovering here, the documentation is displayed, as it should.
/*3*/getLocation: () => "United States",
};
// When hovering here, the documentation is displayed, as it should.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@DanielRosenwasser DanielRosenwasser Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually we should not have comments because they were purely for the repo maintainers. Just drop these.

d: string;
}

type T50 = Getters<Y>; // { getFoo: () => string, getBar: () => number }
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment appears to be copy/pasted and doesn't match the test input (Y only has d, so the mapped type should produce getD). Consider correcting or removing it to keep the test self-explanatory.

Suggested change
type T50 = Getters<Y>; // { getFoo: () => string, getBar: () => number }
type T50 = Getters<Y>; // { getD: () => string }

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just remove the comments. They are lossy artifacts.

d: string;
}

type T50 = Getters<Y>; // { getFoo: () => string, getBar: () => number }
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't match the test input (Y only has d, so the resulting mapped property should be getD). Please correct or remove to avoid misleading documentation in the test case.

Suggested change
type T50 = Getters<Y>; // { getFoo: () => string, getBar: () => number }
type T50 = Getters<Y>; // { getD: () => string }

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +75
// For mapped type symbols with @inheritDoc on the mapped type, synthesize documentation
// from the mapped type's declarations and the syntheticOrigin's declarations.
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says documentation is "synthesized from" mapped type + syntheticOrigin declarations, but the implementation actually returns documentation from the first declaration in the combined list that produces non-empty output. Consider updating the comment (or changing the logic) so the behavior and documentation are consistent.

Suggested change
// For mapped type symbols with @inheritDoc on the mapped type, synthesize documentation
// from the mapped type's declarations and the syntheticOrigin's declarations.
// For mapped type symbols with @inheritDoc on the mapped type, collect documentation
// by considering the mapped type's declarations and the syntheticOrigin's declarations.

Copilot uses AI. Check for mistakes.
Comment on lines 3122 to 3124
pos := p.nodePos()
hasJSDoc := p.jsdocScannerInfo()
p.parseExpected(ast.KindOpenBraceToken)
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasJSDoc is a jsdocScannerInfo bitmask (not a boolean). Renaming it to something like jsdoc/jsdocInfo would better reflect its type and avoid confusion when reading the parser code.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants