diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 0a9740a73e414..2d9d1fe8d28dd 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -2643,7 +2643,7 @@ namespace ts {
const suggestion = getSuggestedSymbolForNonexistentModule(name, targetSymbol);
if (suggestion !== undefined) {
const suggestionName = symbolToString(suggestion);
- const diagnostic = error(name, Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_2, moduleName, declarationName, suggestionName);
+ const diagnostic = error(name, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, moduleName, declarationName, suggestionName);
if (suggestion.valueDeclaration) {
addRelatedInfo(diagnostic,
createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName)
@@ -3020,7 +3020,12 @@ namespace ts {
symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning));
if (!symbol) {
if (!ignoreErrors) {
- error(right, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(namespace), declarationNameToString(right));
+ const namespaceName = getFullyQualifiedName(namespace);
+ const declarationName = declarationNameToString(right);
+ const suggestion = getSuggestedSymbolForNonexistentModule(right, namespace);
+ suggestion ?
+ error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestion)) :
+ error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName);
}
return undefined;
}
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 82f3cb4ce579b..3c4f389085e8b 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -2740,7 +2740,7 @@
"category": "Error",
"code": 2723
},
- "Module '{0}' has no exported member '{1}'. Did you mean '{2}'?": {
+ "'{0}' has no exported member named '{1}'. Did you mean '{2}'?": {
"category": "Error",
"code": 2724
},
@@ -3017,7 +3017,6 @@
"code": 2792
},
-
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts
index 0c63dc5ebfc95..78d748589e837 100644
--- a/src/services/codefixes/fixSpelling.ts
+++ b/src/services/codefixes/fixSpelling.ts
@@ -6,7 +6,7 @@ namespace ts.codefix {
Diagnostics.Cannot_find_name_0_Did_you_mean_1.code,
Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code,
Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0.code,
- Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_2.code,
+ Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2.code,
// for JSX class components
Diagnostics.No_overload_matches_this_call.code,
// for JSX FC
@@ -53,6 +53,12 @@ namespace ts.codefix {
}
suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, containingType);
}
+ else if (isQualifiedName(parent) && parent.right === node) {
+ const symbol = checker.getSymbolAtLocation(parent.left);
+ if (symbol && symbol.flags & SymbolFlags.Module) {
+ suggestedSymbol = checker.getSuggestedSymbolForNonexistentModule(parent.right, symbol);
+ }
+ }
else if (isImportSpecifier(parent) && parent.name === node) {
Debug.assertNode(node, isIdentifier, "Expected an identifier for spelling (import)");
const importDeclaration = findAncestor(node, isImportDeclaration)!;
diff --git a/tests/baselines/reference/exportSpellingSuggestion.errors.txt b/tests/baselines/reference/exportSpellingSuggestion.errors.txt
index 8515003f39cc8..0fa5bbb2415b1 100644
--- a/tests/baselines/reference/exportSpellingSuggestion.errors.txt
+++ b/tests/baselines/reference/exportSpellingSuggestion.errors.txt
@@ -1,4 +1,4 @@
-tests/cases/conformance/es6/modules/b.ts(1,10): error TS2724: Module '"./a"' has no exported member 'assertNevar'. Did you mean 'assertNever'?
+tests/cases/conformance/es6/modules/b.ts(1,10): error TS2724: '"./a"' has no exported member named 'assertNevar'. Did you mean 'assertNever'?
==== tests/cases/conformance/es6/modules/a.ts (0 errors) ====
@@ -9,6 +9,6 @@ tests/cases/conformance/es6/modules/b.ts(1,10): error TS2724: Module '"./a"' has
==== tests/cases/conformance/es6/modules/b.ts (1 errors) ====
import { assertNevar } from "./a";
~~~~~~~~~~~
-!!! error TS2724: Module '"./a"' has no exported member 'assertNevar'. Did you mean 'assertNever'?
+!!! error TS2724: '"./a"' has no exported member named 'assertNevar'. Did you mean 'assertNever'?
!!! related TS2728 tests/cases/conformance/es6/modules/a.ts:1:17: 'assertNever' is declared here.
\ No newline at end of file
diff --git a/tests/baselines/reference/missingMemberErrorHasShortPath.errors.txt b/tests/baselines/reference/missingMemberErrorHasShortPath.errors.txt
index 3cd9e63f5ce85..963c5d9c8caeb 100644
--- a/tests/baselines/reference/missingMemberErrorHasShortPath.errors.txt
+++ b/tests/baselines/reference/missingMemberErrorHasShortPath.errors.txt
@@ -1,4 +1,4 @@
-C:/foo/bar/Baz/src/sample.ts(1,10): error TS2724: Module '"./utils.js"' has no exported member 'exit'. Did you mean 'exist'?
+C:/foo/bar/Baz/src/sample.ts(1,10): error TS2724: '"./utils.js"' has no exported member named 'exit'. Did you mean 'exist'?
==== C:/foo/bar/Baz/src/utils.ts (0 errors) ====
@@ -6,7 +6,7 @@ C:/foo/bar/Baz/src/sample.ts(1,10): error TS2724: Module '"./utils.js"' has no e
==== C:/foo/bar/Baz/src/sample.ts (1 errors) ====
import { exit } from "./utils.js";
~~~~
-!!! error TS2724: Module '"./utils.js"' has no exported member 'exit'. Did you mean 'exist'?
+!!! error TS2724: '"./utils.js"' has no exported member named 'exit'. Did you mean 'exist'?
!!! related TS2728 C:/foo/bar/Baz/src/utils.ts:1:17: 'exist' is declared here.
exit()
\ No newline at end of file
diff --git a/tests/baselines/reference/moduleVisibilityTest3.errors.txt b/tests/baselines/reference/moduleVisibilityTest3.errors.txt
index d901d48c5a8f1..4ff6ff60ce99b 100644
--- a/tests/baselines/reference/moduleVisibilityTest3.errors.txt
+++ b/tests/baselines/reference/moduleVisibilityTest3.errors.txt
@@ -1,6 +1,6 @@
tests/cases/compiler/moduleVisibilityTest3.ts(20,22): error TS2709: Cannot use namespace 'modes' as a type.
-tests/cases/compiler/moduleVisibilityTest3.ts(20,39): error TS2694: Namespace '_modes' has no exported member 'Mode'.
-tests/cases/compiler/moduleVisibilityTest3.ts(21,22): error TS2694: Namespace '_modes' has no exported member 'Mode'.
+tests/cases/compiler/moduleVisibilityTest3.ts(20,39): error TS2724: '_modes' has no exported member named 'Mode'. Did you mean 'IMode'?
+tests/cases/compiler/moduleVisibilityTest3.ts(21,22): error TS2724: '_modes' has no exported member named 'Mode'. Did you mean 'IMode'?
==== tests/cases/compiler/moduleVisibilityTest3.ts (3 errors) ====
@@ -27,10 +27,10 @@ tests/cases/compiler/moduleVisibilityTest3.ts(21,22): error TS2694: Namespace '_
~~~~~
!!! error TS2709: Cannot use namespace 'modes' as a type.
~~~~
-!!! error TS2694: Namespace '_modes' has no exported member 'Mode'.
+!!! error TS2724: '_modes' has no exported member named 'Mode'. Did you mean 'IMode'?
var x:modes.Mode;
~~~~
-!!! error TS2694: Namespace '_modes' has no exported member 'Mode'.
+!!! error TS2724: '_modes' has no exported member named 'Mode'. Did you mean 'IMode'?
}
}
diff --git a/tests/baselines/reference/moduleVisibilityTest4.errors.txt b/tests/baselines/reference/moduleVisibilityTest4.errors.txt
new file mode 100644
index 0000000000000..3c36d0df3e0e4
--- /dev/null
+++ b/tests/baselines/reference/moduleVisibilityTest4.errors.txt
@@ -0,0 +1,31 @@
+tests/cases/compiler/moduleVisibilityTest4.ts(9,11): error TS2724: 'M' has no exported member named 'num'. Did you mean 'nums'?
+tests/cases/compiler/moduleVisibilityTest4.ts(11,11): error TS2694: Namespace 'M' has no exported member 'bar'.
+tests/cases/compiler/moduleVisibilityTest4.ts(13,11): error TS2724: 'N' has no exported member named 'num'. Did you mean 'nums'?
+tests/cases/compiler/moduleVisibilityTest4.ts(15,11): error TS2694: Namespace 'N' has no exported member 'bar'.
+
+
+==== tests/cases/compiler/moduleVisibilityTest4.ts (4 errors) ====
+ module M {
+ export type nums = number;
+ }
+
+ namespace N {
+ export type nums = number;
+ }
+
+ let a1: M.num;
+ ~~~
+!!! error TS2724: 'M' has no exported member named 'num'. Did you mean 'nums'?
+ let b1: M.nums;
+ let c1: M.bar;
+ ~~~
+!!! error TS2694: Namespace 'M' has no exported member 'bar'.
+
+ let a2: N.num;
+ ~~~
+!!! error TS2724: 'N' has no exported member named 'num'. Did you mean 'nums'?
+ let b2: N.nums;
+ let c2: N.bar;
+ ~~~
+!!! error TS2694: Namespace 'N' has no exported member 'bar'.
+
\ No newline at end of file
diff --git a/tests/baselines/reference/moduleVisibilityTest4.js b/tests/baselines/reference/moduleVisibilityTest4.js
new file mode 100644
index 0000000000000..35fb39ea95ff2
--- /dev/null
+++ b/tests/baselines/reference/moduleVisibilityTest4.js
@@ -0,0 +1,25 @@
+//// [moduleVisibilityTest4.ts]
+module M {
+ export type nums = number;
+}
+
+namespace N {
+ export type nums = number;
+}
+
+let a1: M.num;
+let b1: M.nums;
+let c1: M.bar;
+
+let a2: N.num;
+let b2: N.nums;
+let c2: N.bar;
+
+
+//// [moduleVisibilityTest4.js]
+var a1;
+var b1;
+var c1;
+var a2;
+var b2;
+var c2;
diff --git a/tests/baselines/reference/moduleVisibilityTest4.symbols b/tests/baselines/reference/moduleVisibilityTest4.symbols
new file mode 100644
index 0000000000000..410dbb5a2d9bb
--- /dev/null
+++ b/tests/baselines/reference/moduleVisibilityTest4.symbols
@@ -0,0 +1,41 @@
+=== tests/cases/compiler/moduleVisibilityTest4.ts ===
+module M {
+>M : Symbol(M, Decl(moduleVisibilityTest4.ts, 0, 0))
+
+ export type nums = number;
+>nums : Symbol(nums, Decl(moduleVisibilityTest4.ts, 0, 10))
+}
+
+namespace N {
+>N : Symbol(N, Decl(moduleVisibilityTest4.ts, 2, 1))
+
+ export type nums = number;
+>nums : Symbol(nums, Decl(moduleVisibilityTest4.ts, 4, 13))
+}
+
+let a1: M.num;
+>a1 : Symbol(a1, Decl(moduleVisibilityTest4.ts, 8, 3))
+>M : Symbol(M, Decl(moduleVisibilityTest4.ts, 0, 0))
+
+let b1: M.nums;
+>b1 : Symbol(b1, Decl(moduleVisibilityTest4.ts, 9, 3))
+>M : Symbol(M, Decl(moduleVisibilityTest4.ts, 0, 0))
+>nums : Symbol(M.nums, Decl(moduleVisibilityTest4.ts, 0, 10))
+
+let c1: M.bar;
+>c1 : Symbol(c1, Decl(moduleVisibilityTest4.ts, 10, 3))
+>M : Symbol(M, Decl(moduleVisibilityTest4.ts, 0, 0))
+
+let a2: N.num;
+>a2 : Symbol(a2, Decl(moduleVisibilityTest4.ts, 12, 3))
+>N : Symbol(N, Decl(moduleVisibilityTest4.ts, 2, 1))
+
+let b2: N.nums;
+>b2 : Symbol(b2, Decl(moduleVisibilityTest4.ts, 13, 3))
+>N : Symbol(N, Decl(moduleVisibilityTest4.ts, 2, 1))
+>nums : Symbol(N.nums, Decl(moduleVisibilityTest4.ts, 4, 13))
+
+let c2: N.bar;
+>c2 : Symbol(c2, Decl(moduleVisibilityTest4.ts, 14, 3))
+>N : Symbol(N, Decl(moduleVisibilityTest4.ts, 2, 1))
+
diff --git a/tests/baselines/reference/moduleVisibilityTest4.types b/tests/baselines/reference/moduleVisibilityTest4.types
new file mode 100644
index 0000000000000..d00eccc0bec3e
--- /dev/null
+++ b/tests/baselines/reference/moduleVisibilityTest4.types
@@ -0,0 +1,35 @@
+=== tests/cases/compiler/moduleVisibilityTest4.ts ===
+module M {
+ export type nums = number;
+>nums : number
+}
+
+namespace N {
+ export type nums = number;
+>nums : number
+}
+
+let a1: M.num;
+>a1 : any
+>M : any
+
+let b1: M.nums;
+>b1 : number
+>M : any
+
+let c1: M.bar;
+>c1 : any
+>M : any
+
+let a2: N.num;
+>a2 : any
+>N : any
+
+let b2: N.nums;
+>b2 : number
+>N : any
+
+let c2: N.bar;
+>c2 : any
+>N : any
+
diff --git a/tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/with---outFile-and-multiple-declaration-files-in-the-program.js b/tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/with---outFile-and-multiple-declaration-files-in-the-program.js
index 249c18eb769de..fb796e3dd482d 100644
--- a/tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/with---outFile-and-multiple-declaration-files-in-the-program.js
+++ b/tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/with---outFile-and-multiple-declaration-files-in-the-program.js
@@ -34,7 +34,7 @@ Output::
[[90m12:00:31 AM[0m] Starting compilation in watch mode...
-[96ma/b/project/src/main2.ts[0m:[93m1[0m:[93m114[0m - [91merror[0m[90m TS2694: [0mNamespace 'Common.SomeComponent.DynamicMenu' has no exported member 'z'.
+[96ma/b/project/src/main2.ts[0m:[93m1[0m:[93m114[0m - [91merror[0m[90m TS2724: [0m'Common.SomeComponent.DynamicMenu' has no exported member named 'z'. Did you mean 'Z'?
[7m1[0m namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }
[7m [0m [91m ~[0m
diff --git a/tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/without---outFile-and-multiple-declaration-files-in-the-program.js b/tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/without---outFile-and-multiple-declaration-files-in-the-program.js
index c1a9b5adeadef..011290a833a80 100644
--- a/tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/without---outFile-and-multiple-declaration-files-in-the-program.js
+++ b/tests/baselines/reference/tscWatch/emit/emit-with-outFile-or-out-setting/without---outFile-and-multiple-declaration-files-in-the-program.js
@@ -34,7 +34,7 @@ Output::
[[90m12:00:31 AM[0m] Starting compilation in watch mode...
-[96ma/b/project/src/main2.ts[0m:[93m1[0m:[93m114[0m - [91merror[0m[90m TS2694: [0mNamespace 'Common.SomeComponent.DynamicMenu' has no exported member 'z'.
+[96ma/b/project/src/main2.ts[0m:[93m1[0m:[93m114[0m - [91merror[0m[90m TS2724: [0m'Common.SomeComponent.DynamicMenu' has no exported member named 'z'. Did you mean 'Z'?
[7m1[0m namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }
[7m [0m [91m ~[0m
diff --git a/tests/cases/compiler/moduleVisibilityTest4.ts b/tests/cases/compiler/moduleVisibilityTest4.ts
new file mode 100644
index 0000000000000..ee749b6f7f25f
--- /dev/null
+++ b/tests/cases/compiler/moduleVisibilityTest4.ts
@@ -0,0 +1,15 @@
+module M {
+ export type nums = number;
+}
+
+namespace N {
+ export type nums = number;
+}
+
+let a1: M.num;
+let b1: M.nums;
+let c1: M.bar;
+
+let a2: N.num;
+let b2: N.nums;
+let c2: N.bar;
diff --git a/tests/cases/fourslash/codeFixSpelling7.ts b/tests/cases/fourslash/codeFixSpelling7.ts
new file mode 100644
index 0000000000000..9b7e809f8ff92
--- /dev/null
+++ b/tests/cases/fourslash/codeFixSpelling7.ts
@@ -0,0 +1,12 @@
+///
+
+////namespace Foo {
+//// export type nums = number;
+////}
+////let x: Foo.[|num|];
+
+verify.codeFix({
+ index: 0,
+ description: [ts.Diagnostics.Change_spelling_to_0.message, "nums"],
+ newRangeContent: "nums"
+});
diff --git a/tests/cases/fourslash/codeFixSpelling8.ts b/tests/cases/fourslash/codeFixSpelling8.ts
new file mode 100644
index 0000000000000..c4df4e1cebeb9
--- /dev/null
+++ b/tests/cases/fourslash/codeFixSpelling8.ts
@@ -0,0 +1,12 @@
+///
+
+////module Foo {
+//// export type nums = number;
+////}
+////let x: Foo.[|num|];
+
+verify.codeFix({
+ index: 0,
+ description: [ts.Diagnostics.Change_spelling_to_0.message, "nums"],
+ newRangeContent: "nums"
+});
diff --git a/tests/cases/fourslash/codeFixSpelling9.ts b/tests/cases/fourslash/codeFixSpelling9.ts
new file mode 100644
index 0000000000000..6dd76cd76a679
--- /dev/null
+++ b/tests/cases/fourslash/codeFixSpelling9.ts
@@ -0,0 +1,15 @@
+///
+
+// @filename: a.ts
+////module Foo {
+//// export type nums = number;
+////}
+// @filename: b.ts
+////let x: Foo.[|num|];
+
+goTo.file("b.ts");
+verify.codeFix({
+ index: 0,
+ description: [ts.Diagnostics.Change_spelling_to_0.message, "nums"],
+ newRangeContent: "nums"
+});