feat(4294): report deprecated diagnostics for contextual props (microsoft/typescript-go#4309)

This commit is contained in:
Oleksandr Tarasiuk authored and GitHub committed 2026-07-29 22:27:14 +00:00
1 parent 877e9e2db9
commit db9c67cd31
6 files changed
+106 -10

No files matched your search

+16
View File
@@ -13267,6 +13267,9 @@ func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type
if allPropertiesTable != nil {
allPropertiesTable[prop.Name] = prop
}
if ast.IsIdentifier(memberDecl.Name()) {
c.checkDeprecatedProperty(memberDecl.Name(), contextualType)
}
if contextualType != nil && checkMode&CheckModeInferential != 0 && checkMode&CheckModeSkipContextSensitive == 0 && (ast.IsPropertyAssignment(memberDecl) || ast.IsMethodDeclaration(memberDecl)) && c.isContextSensitive(memberDecl) {
inferenceContext := c.getInferenceContext(node)
// In CheckMode.Inferential we should always have an inference context
@@ -13351,6 +13354,19 @@ func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type
return createObjectLiteralType()
}
func (c *Checker) checkDeprecatedProperty(name *ast.IdentifierNode, contextualType *Type) {
if contextualType == nil || name == nil {
return
}
prop := c.getPropertyOfType(contextualType, name.Text())
if prop == nil || len(prop.Declarations) == 0 {
return
}
if c.isDeprecatedSymbol(prop) {
c.addDeprecatedSuggestion(name, prop.Declarations, name.Text())
}
}
func (c *Checker) checkSpreadPropOverrides(t *Type, props ast.SymbolTable, spread *ast.Node) {
for _, right := range c.getPropertiesOfType(t) {
if right.Flags&ast.SymbolFlagsOptional == 0 && right.CheckFlags&ast.CheckFlagsPartial == 0 {
+2 -5
View File
@@ -756,11 +756,8 @@ func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeEleme
if attributeDecl.Name().Text() == jsxChildrenPropertyName {
explicitlySpecifyChildrenAttribute = true
}
if contextualType != nil {
prop := c.getPropertyOfType(contextualType, member.Name)
if prop != nil && prop.Declarations != nil && c.isDeprecatedSymbol(prop) && ast.IsIdentifier(attributeDecl.Name()) {
c.addDeprecatedSuggestion(attributeDecl.Name(), prop.Declarations, attributeDecl.Name().Text())
}
if ast.IsIdentifier(attributeDecl.Name()) {
c.checkDeprecatedProperty(attributeDecl.Name(), contextualType)
}
if contextualType != nil && checkMode&CheckModeInferential != 0 && checkMode&CheckModeSkipContextSensitive == 0 && c.isContextSensitive(attributeDecl) {
inferenceContext := c.getInferenceContext(attributes)
@@ -81,6 +81,7 @@ importNameCodeFixOptionalImport0
incrementalParsingWithJsDoc
isDefinitionAcrossGlobalProjects
jsdocDeprecated_suggestion1
jsdocDeprecated_suggestion19
jsdocDeprecated_suggestion2
jsDocFunctionSignatures12
jsDocFunctionSignatures2
@@ -1,6 +1,3 @@
// Code generated by convertFourslash; DO NOT EDIT.
// To modify this test, run "npm run makemanual jsdocDeprecated_suggestion19"
package fourslash_test
import (
@@ -12,7 +9,6 @@ import (
)
func TestJsdocDeprecated_suggestion19(t *testing.T) {
fourslash.SkipIfFailing(t)
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `interface I {
@@ -23,7 +19,7 @@ interface I {
/** @deprecated */
x: number;
}
const foo: I = { x: 1, y: 1 };
const foo: I = { [|x|]: 1, y: 1 };
foo.[|x|];`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
@@ -34,5 +30,11 @@ foo.[|x|];`
Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated},
Range: f.Ranges()[0].LSRange,
},
{
Code: &lsproto.IntegerOrString{Integer: new(int32(6385))},
Message: lsproto.StringOrMarkupContent{String: new("'x' is deprecated.")},
Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated},
Range: f.Ranges()[1].LSRange,
},
})
}
@@ -0,0 +1,42 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestJsdocDeprecated_suggestion3(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `interface RequestOptions {
/** @deprecated use signal instead */
timeout?: number;
}
declare function request(url: string, opts: RequestOptions): void;
request("/api", { [|timeout|]: 5000 });
declare const opts: RequestOptions;
opts.[|timeout|];`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifySuggestionDiagnostics(t, []*lsproto.Diagnostic{
{
Code: &lsproto.IntegerOrString{Integer: new(int32(6385))},
Message: lsproto.StringOrMarkupContent{String: new("'timeout' is deprecated.")},
Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated},
Range: f.Ranges()[0].LSRange,
},
{
Code: &lsproto.IntegerOrString{Integer: new(int32(6385))},
Message: lsproto.StringOrMarkupContent{String: new("'timeout' is deprecated.")},
Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated},
Range: f.Ranges()[1].LSRange,
},
})
}
@@ -0,0 +1,38 @@
package fourslash_test
import (
"testing"
"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/testutil"
)
func TestJsdocDeprecated_suggestion4(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `// @jsx: preserve
// @filename: a.tsx
interface Props {
/** @deprecated */
x: number
y: number
}
function A(props: Props) {
return <div>{props.y}</div>
}
function B() {
return <A [|x|]={1} y={1} />
}`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.GoToFile(t, "a.tsx")
f.VerifySuggestionDiagnostics(t, []*lsproto.Diagnostic{
{
Message: lsproto.StringOrMarkupContent{String: new("'x' is deprecated.")},
Code: &lsproto.IntegerOrString{Integer: new(int32(6385))},
Range: f.Ranges()[0].LSRange,
Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated},
},
})
}