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:: [12:00:31 AM] Starting compilation in watch mode... -a/b/project/src/main2.ts:1:114 - error TS2694: Namespace 'Common.SomeComponent.DynamicMenu' has no exported member 'z'. +a/b/project/src/main2.ts:1:114 - error TS2724: 'Common.SomeComponent.DynamicMenu' has no exported member named 'z'. Did you mean 'Z'? 1 namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }    ~ 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:: [12:00:31 AM] Starting compilation in watch mode... -a/b/project/src/main2.ts:1:114 - error TS2694: Namespace 'Common.SomeComponent.DynamicMenu' has no exported member 'z'. +a/b/project/src/main2.ts:1:114 - error TS2724: 'Common.SomeComponent.DynamicMenu' has no exported member named 'z'. Did you mean 'Z'? 1 namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }    ~ 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" +});