Skip to content

Commit a9e089d

Browse files
committed
feat(part of 40169): add spelling suggestion/quick fix for module/namespace exported members
1 parent 610fa28 commit a9e089d

14 files changed

+209
-8
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3020,7 +3020,12 @@ namespace ts {
30203020
symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning));
30213021
if (!symbol) {
30223022
if (!ignoreErrors) {
3023-
error(right, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(namespace), declarationNameToString(right));
3023+
const namespaceName = getFullyQualifiedName(namespace);
3024+
const declarationName = declarationNameToString(right);
3025+
const suggestion = getSuggestedSymbolForNonexistentModule(right, namespace);
3026+
suggestion ?
3027+
error(right, Diagnostics.Namespace_0_has_no_exported_member_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestion)) :
3028+
error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName);
30243029
}
30253030
return undefined;
30263031
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3016,7 +3016,10 @@
30163016
"category": "Error",
30173017
"code": 2792
30183018
},
3019-
3019+
"Namespace '{0}' has no exported member '{1}'. Did you mean '{2}'?": {
3020+
"category": "Error",
3021+
"code": 2793
3022+
},
30203023

30213024
"Import declaration '{0}' is using private name '{1}'.": {
30223025
"category": "Error",

src/services/codefixes/fixSpelling.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace ts.codefix {
77
Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code,
88
Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0.code,
99
Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_2.code,
10+
Diagnostics.Namespace_0_has_no_exported_member_1_Did_you_mean_2.code,
1011
// for JSX class components
1112
Diagnostics.No_overload_matches_this_call.code,
1213
// for JSX FC
@@ -53,6 +54,12 @@ namespace ts.codefix {
5354
}
5455
suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, containingType);
5556
}
57+
else if (isQualifiedName(parent) && parent.right === node) {
58+
const symbol = checker.getSymbolAtLocation(parent.left);
59+
if (symbol && symbol.flags & SymbolFlags.Module) {
60+
suggestedSymbol = checker.getSuggestedSymbolForNonexistentModule(parent.right, symbol);
61+
}
62+
}
5663
else if (isImportSpecifier(parent) && parent.name === node) {
5764
Debug.assertNode(node, isIdentifier, "Expected an identifier for spelling (import)");
5865
const importDeclaration = findAncestor(node, isImportDeclaration)!;

tests/baselines/reference/moduleVisibilityTest3.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
tests/cases/compiler/moduleVisibilityTest3.ts(20,22): error TS2709: Cannot use namespace 'modes' as a type.
2-
tests/cases/compiler/moduleVisibilityTest3.ts(20,39): error TS2694: Namespace '_modes' has no exported member 'Mode'.
3-
tests/cases/compiler/moduleVisibilityTest3.ts(21,22): error TS2694: Namespace '_modes' has no exported member 'Mode'.
2+
tests/cases/compiler/moduleVisibilityTest3.ts(20,39): error TS2793: Namespace '_modes' has no exported member 'Mode'. Did you mean 'IMode'?
3+
tests/cases/compiler/moduleVisibilityTest3.ts(21,22): error TS2793: Namespace '_modes' has no exported member 'Mode'. Did you mean 'IMode'?
44

55

66
==== tests/cases/compiler/moduleVisibilityTest3.ts (3 errors) ====
@@ -27,10 +27,10 @@ tests/cases/compiler/moduleVisibilityTest3.ts(21,22): error TS2694: Namespace '_
2727
~~~~~
2828
!!! error TS2709: Cannot use namespace 'modes' as a type.
2929
~~~~
30-
!!! error TS2694: Namespace '_modes' has no exported member 'Mode'.
30+
!!! error TS2793: Namespace '_modes' has no exported member 'Mode'. Did you mean 'IMode'?
3131
var x:modes.Mode;
3232
~~~~
33-
!!! error TS2694: Namespace '_modes' has no exported member 'Mode'.
33+
!!! error TS2793: Namespace '_modes' has no exported member 'Mode'. Did you mean 'IMode'?
3434
}
3535

3636
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
tests/cases/compiler/moduleVisibilityTest4.ts(9,11): error TS2793: Namespace 'M' has no exported member 'num'. Did you mean 'nums'?
2+
tests/cases/compiler/moduleVisibilityTest4.ts(11,11): error TS2694: Namespace 'M' has no exported member 'bar'.
3+
tests/cases/compiler/moduleVisibilityTest4.ts(13,11): error TS2793: Namespace 'N' has no exported member 'num'. Did you mean 'nums'?
4+
tests/cases/compiler/moduleVisibilityTest4.ts(15,11): error TS2694: Namespace 'N' has no exported member 'bar'.
5+
6+
7+
==== tests/cases/compiler/moduleVisibilityTest4.ts (4 errors) ====
8+
module M {
9+
export type nums = number;
10+
}
11+
12+
namespace N {
13+
export type nums = number;
14+
}
15+
16+
let a1: M.num;
17+
~~~
18+
!!! error TS2793: Namespace 'M' has no exported member 'num'. Did you mean 'nums'?
19+
let b1: M.nums;
20+
let c1: M.bar;
21+
~~~
22+
!!! error TS2694: Namespace 'M' has no exported member 'bar'.
23+
24+
let a2: N.num;
25+
~~~
26+
!!! error TS2793: Namespace 'N' has no exported member 'num'. Did you mean 'nums'?
27+
let b2: N.nums;
28+
let c2: N.bar;
29+
~~~
30+
!!! error TS2694: Namespace 'N' has no exported member 'bar'.
31+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [moduleVisibilityTest4.ts]
2+
module M {
3+
export type nums = number;
4+
}
5+
6+
namespace N {
7+
export type nums = number;
8+
}
9+
10+
let a1: M.num;
11+
let b1: M.nums;
12+
let c1: M.bar;
13+
14+
let a2: N.num;
15+
let b2: N.nums;
16+
let c2: N.bar;
17+
18+
19+
//// [moduleVisibilityTest4.js]
20+
var a1;
21+
var b1;
22+
var c1;
23+
var a2;
24+
var b2;
25+
var c2;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
=== tests/cases/compiler/moduleVisibilityTest4.ts ===
2+
module M {
3+
>M : Symbol(M, Decl(moduleVisibilityTest4.ts, 0, 0))
4+
5+
export type nums = number;
6+
>nums : Symbol(nums, Decl(moduleVisibilityTest4.ts, 0, 10))
7+
}
8+
9+
namespace N {
10+
>N : Symbol(N, Decl(moduleVisibilityTest4.ts, 2, 1))
11+
12+
export type nums = number;
13+
>nums : Symbol(nums, Decl(moduleVisibilityTest4.ts, 4, 13))
14+
}
15+
16+
let a1: M.num;
17+
>a1 : Symbol(a1, Decl(moduleVisibilityTest4.ts, 8, 3))
18+
>M : Symbol(M, Decl(moduleVisibilityTest4.ts, 0, 0))
19+
20+
let b1: M.nums;
21+
>b1 : Symbol(b1, Decl(moduleVisibilityTest4.ts, 9, 3))
22+
>M : Symbol(M, Decl(moduleVisibilityTest4.ts, 0, 0))
23+
>nums : Symbol(M.nums, Decl(moduleVisibilityTest4.ts, 0, 10))
24+
25+
let c1: M.bar;
26+
>c1 : Symbol(c1, Decl(moduleVisibilityTest4.ts, 10, 3))
27+
>M : Symbol(M, Decl(moduleVisibilityTest4.ts, 0, 0))
28+
29+
let a2: N.num;
30+
>a2 : Symbol(a2, Decl(moduleVisibilityTest4.ts, 12, 3))
31+
>N : Symbol(N, Decl(moduleVisibilityTest4.ts, 2, 1))
32+
33+
let b2: N.nums;
34+
>b2 : Symbol(b2, Decl(moduleVisibilityTest4.ts, 13, 3))
35+
>N : Symbol(N, Decl(moduleVisibilityTest4.ts, 2, 1))
36+
>nums : Symbol(N.nums, Decl(moduleVisibilityTest4.ts, 4, 13))
37+
38+
let c2: N.bar;
39+
>c2 : Symbol(c2, Decl(moduleVisibilityTest4.ts, 14, 3))
40+
>N : Symbol(N, Decl(moduleVisibilityTest4.ts, 2, 1))
41+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
=== tests/cases/compiler/moduleVisibilityTest4.ts ===
2+
module M {
3+
export type nums = number;
4+
>nums : number
5+
}
6+
7+
namespace N {
8+
export type nums = number;
9+
>nums : number
10+
}
11+
12+
let a1: M.num;
13+
>a1 : any
14+
>M : any
15+
16+
let b1: M.nums;
17+
>b1 : number
18+
>M : any
19+
20+
let c1: M.bar;
21+
>c1 : any
22+
>M : any
23+
24+
let a2: N.num;
25+
>a2 : any
26+
>N : any
27+
28+
let b2: N.nums;
29+
>b2 : number
30+
>N : any
31+
32+
let c2: N.bar;
33+
>c2 : any
34+
>N : any
35+

tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/with---outFile-and-multiple-declaration-files-in-the-program.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Output::
3434
[12:00:31 AM] Starting compilation in watch mode...
3535

3636

37-
[96ma/b/project/src/main2.ts[0m:[93m1[0m:[93m114[0m - [91merror[0m[90m TS2694: [0mNamespace 'Common.SomeComponent.DynamicMenu' has no exported member 'z'.
37+
[96ma/b/project/src/main2.ts[0m:[93m1[0m:[93m114[0m - [91merror[0m[90m TS2793: [0mNamespace 'Common.SomeComponent.DynamicMenu' has no exported member 'z'. Did you mean 'Z'?
3838

3939
1 namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }
4040
   ~

tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/without---outFile-and-multiple-declaration-files-in-the-program.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Output::
3434
[12:00:31 AM] Starting compilation in watch mode...
3535

3636

37-
[96ma/b/project/src/main2.ts[0m:[93m1[0m:[93m114[0m - [91merror[0m[90m TS2694: [0mNamespace 'Common.SomeComponent.DynamicMenu' has no exported member 'z'.
37+
[96ma/b/project/src/main2.ts[0m:[93m1[0m:[93m114[0m - [91merror[0m[90m TS2793: [0mNamespace 'Common.SomeComponent.DynamicMenu' has no exported member 'z'. Did you mean 'Z'?
3838

3939
1 namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }
4040
   ~

0 commit comments

Comments
 (0)