From 9deb3be53de78feb4f25b20eed107597635a9657 Mon Sep 17 00:00:00 2001 From: mato2512 Date: Sun, 18 Oct 2026 11:25:58 +0530 Subject: [PATCH 1/2] Support @deprecated marker on namespace aliases (fixes #62340) --- tsc/internal/checker/checker.go | 22 +++++++++++--- tsc/internal/checker/checker_test.go | 44 ++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 10ddb3c0c88b4..d9045e35cb1ad 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -3078,10 +3078,24 @@ func (c *Checker) checkTypeReferenceOrImport(node *ast.Node) { c.checkTypeArgumentConstraints(node, typeParameters) } } - symbol := c.getResolvedSymbolOrNil(node) - if symbol != nil { - if core.Some(symbol.Declarations(), func(d *ast.Node) bool { return ast.IsTypeDeclaration(d) && c.IsDeprecatedDeclaration(d) }) { - c.addDeprecatedSuggestion(c.getDeprecatedSuggestionNode(node), symbol.Declarations(), symbol.Name()) + name := getTypeReferenceName(node) + var aliasSymbol *ast.Symbol + if name != nil { + aliasSymbol = c.resolveEntityName(name, ast.SymbolFlagsType, true /*ignoreErrors*/, true /*dontResolveAlias*/, nil /*location*/) + } + if aliasSymbol != nil && aliasSymbol.Flags()&ast.SymbolFlagsAlias != 0 { + targetSymbol := c.resolveAliasWithDeprecationCheck(aliasSymbol, c.getDeprecatedSuggestionNode(node)) + if targetSymbol != nil && core.Some(targetSymbol.Declarations(), func(d *ast.Node) bool { + return (ast.IsTypeDeclaration(d) || d.Kind == ast.KindImportEqualsDeclaration || d.Kind == ast.KindImportSpecifier) && c.IsDeprecatedDeclaration(d) + }) { + c.addDeprecatedSuggestion(c.getDeprecatedSuggestionNode(node), targetSymbol.Declarations(), targetSymbol.Name()) + } + } else { + symbol := c.getResolvedSymbolOrNil(node) + if symbol != nil { + if core.Some(symbol.Declarations(), func(d *ast.Node) bool { return ast.IsTypeDeclaration(d) && c.IsDeprecatedDeclaration(d) }) { + c.addDeprecatedSuggestion(c.getDeprecatedSuggestionNode(node), symbol.Declarations(), symbol.Name()) + } } } } diff --git a/tsc/internal/checker/checker_test.go b/tsc/internal/checker/checker_test.go index 31cea19751525..f60592728d34e 100644 --- a/tsc/internal/checker/checker_test.go +++ b/tsc/internal/checker/checker_test.go @@ -208,3 +208,47 @@ export type Initial = Box<"first">; assert.Equal(t, c.TypeToString(initial), "Initial") assert.Equal(t, len(c.GetDiagnostics(t.Context(), file)), 0) } + +func TestDeprecatedNamespaceAliasInTypeReference(t *testing.T) { + t.Parallel() + + fs := bundled.WrapFS(vfstest.FromMap(map[string]string{ + "/example.d.ts": `export type Bar = string | number; +/** @deprecated */ +export type Baz = string | number;`, + "/foo.ts": `import * as example from './example'; + +declare namespace JSX { + /** @deprecated */ + export type Foo = string | number; + + /** @deprecated */ + export import Bar = example.Bar; + + export import Baz = example.Baz; +} + +let x: JSX.Foo; +let y: JSX.Bar; +let z: JSX.Baz;`, + }, tspath.CaseSensitive)) + opts := &core.CompilerOptions{NoLib: core.TSTrue} + program := compiler.NewProgram(compiler.ProgramOptions{ + Config: tsoptions.NewParsedCommandLine(opts, []tspath.RootedFilePath{"/example.d.ts", "/foo.ts"}, nil, "/", fs.CaseSensitivity()), + Host: compiler.NewCompilerHost(fs, bundled.LibPath(), nil, nil, nil), + }) + program.BindSourceFiles() + c, done := program.GetTypeChecker(t.Context()) + defer done() + file := program.GetSourceFile("/foo.ts") + var deprecatedSuggestions []*ast.Diagnostic + for _, s := range c.GetSuggestionDiagnostics(t.Context(), file) { + if s.ReportsDeprecated() { + deprecatedSuggestions = append(deprecatedSuggestions, s) + } + } + assert.Equal(t, len(deprecatedSuggestions), 3) + assert.Equal(t, deprecatedSuggestions[0].MessageArgs()[0], "Foo") + assert.Equal(t, deprecatedSuggestions[1].MessageArgs()[0], "Bar") + assert.Equal(t, deprecatedSuggestions[2].MessageArgs()[0], "Baz") +} From f2ca4759bbd6af32fe58d3df901025e045ff8d73 Mon Sep 17 00:00:00 2001 From: mato2512 Date: Sun, 18 Oct 2026 13:30:21 +0530 Subject: [PATCH 2/2] Address Copilot review feedback on import types, merged symbols, and export specifiers --- tsc/internal/checker/checker.go | 14 ++++++++++++-- tsc/internal/checker/checker_test.go | 24 +++++++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index d9045e35cb1ad..b4975ec3a77be 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -3082,11 +3082,13 @@ func (c *Checker) checkTypeReferenceOrImport(node *ast.Node) { var aliasSymbol *ast.Symbol if name != nil { aliasSymbol = c.resolveEntityName(name, ast.SymbolFlagsType, true /*ignoreErrors*/, true /*dontResolveAlias*/, nil /*location*/) + } else if ast.IsImportTypeNode(node) && !ast.NodeIsMissing(node.AsImportTypeNode().Qualifier) { + aliasSymbol = c.getResolvedSymbolOrNil(node.AsImportTypeNode().Qualifier) } - if aliasSymbol != nil && aliasSymbol.Flags()&ast.SymbolFlagsAlias != 0 { + if aliasSymbol != nil && aliasSymbol.Flags()&ast.SymbolFlagsAlias != 0 && aliasSymbol.Flags()&ast.SymbolFlagsType == 0 { targetSymbol := c.resolveAliasWithDeprecationCheck(aliasSymbol, c.getDeprecatedSuggestionNode(node)) if targetSymbol != nil && core.Some(targetSymbol.Declarations(), func(d *ast.Node) bool { - return (ast.IsTypeDeclaration(d) || d.Kind == ast.KindImportEqualsDeclaration || d.Kind == ast.KindImportSpecifier) && c.IsDeprecatedDeclaration(d) + return (ast.IsTypeDeclaration(d) || d.Kind == ast.KindImportEqualsDeclaration || d.Kind == ast.KindImportSpecifier || d.Kind == ast.KindExportSpecifier) && c.IsDeprecatedDeclaration(d) }) { c.addDeprecatedSuggestion(c.getDeprecatedSuggestionNode(node), targetSymbol.Declarations(), targetSymbol.Name()) } @@ -3136,6 +3138,14 @@ func (c *Checker) getDeprecatedSuggestionNode(node *ast.Node) *ast.Node { if ast.IsQualifiedName(typeName) { return typeName.AsQualifiedName().Right } + case ast.KindImportType: + qualifier := node.AsImportTypeNode().Qualifier + if qualifier != nil { + if ast.IsQualifiedName(qualifier) { + return qualifier.AsQualifiedName().Right + } + return qualifier + } } return node } diff --git a/tsc/internal/checker/checker_test.go b/tsc/internal/checker/checker_test.go index f60592728d34e..429ee39b1aa7c 100644 --- a/tsc/internal/checker/checker_test.go +++ b/tsc/internal/checker/checker_test.go @@ -215,10 +215,16 @@ func TestDeprecatedNamespaceAliasInTypeReference(t *testing.T) { fs := bundled.WrapFS(vfstest.FromMap(map[string]string{ "/example.d.ts": `export type Bar = string | number; /** @deprecated */ -export type Baz = string | number;`, +export type Baz = string | number; +export { /** @deprecated */ Bar as Old } from './example';`, + "/values.d.ts": `export const val = 1;`, "/foo.ts": `import * as example from './example'; -declare namespace JSX { +export { val } from './values'; +/** @deprecated */ +export type val = number; + +export namespace JSX { /** @deprecated */ export type Foo = string | number; @@ -226,15 +232,20 @@ declare namespace JSX { export import Bar = example.Bar; export import Baz = example.Baz; + + export import Old = example.Old; } let x: JSX.Foo; let y: JSX.Bar; -let z: JSX.Baz;`, +let z: JSX.Baz; +let o: JSX.Old; +let m: val; +let w: import('./foo').JSX.Bar;`, }, tspath.CaseSensitive)) opts := &core.CompilerOptions{NoLib: core.TSTrue} program := compiler.NewProgram(compiler.ProgramOptions{ - Config: tsoptions.NewParsedCommandLine(opts, []tspath.RootedFilePath{"/example.d.ts", "/foo.ts"}, nil, "/", fs.CaseSensitivity()), + Config: tsoptions.NewParsedCommandLine(opts, []tspath.RootedFilePath{"/example.d.ts", "/values.d.ts", "/foo.ts"}, nil, "/", fs.CaseSensitivity()), Host: compiler.NewCompilerHost(fs, bundled.LibPath(), nil, nil, nil), }) program.BindSourceFiles() @@ -247,8 +258,11 @@ let z: JSX.Baz;`, deprecatedSuggestions = append(deprecatedSuggestions, s) } } - assert.Equal(t, len(deprecatedSuggestions), 3) + assert.Equal(t, len(deprecatedSuggestions), 6) assert.Equal(t, deprecatedSuggestions[0].MessageArgs()[0], "Foo") assert.Equal(t, deprecatedSuggestions[1].MessageArgs()[0], "Bar") assert.Equal(t, deprecatedSuggestions[2].MessageArgs()[0], "Baz") + assert.Equal(t, deprecatedSuggestions[3].MessageArgs()[0], "Old") + assert.Equal(t, deprecatedSuggestions[4].MessageArgs()[0], "val") + assert.Equal(t, deprecatedSuggestions[5].MessageArgs()[0], "Bar") }