Skip to content

Commit b151573

Browse files
Kingwlsandersn
authored andcommitted
add spelling suggestion support for module import (#22283)
1 parent dd27288 commit b151573

7 files changed

+92
-1
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1857,7 +1857,15 @@ namespace ts {
18571857
combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) :
18581858
symbolFromModule || symbolFromVariable;
18591859
if (!symbol) {
1860-
error(name, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(moduleSymbol), declarationNameToString(name));
1860+
const moduleName = getFullyQualifiedName(moduleSymbol);
1861+
const declarationName = declarationNameToString(name);
1862+
const suggestion = getSuggestionForNonexistentModule(name, targetSymbol);
1863+
if (suggestion !== undefined) {
1864+
error(name, Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_2, moduleName, declarationName, suggestion);
1865+
}
1866+
else {
1867+
error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName);
1868+
}
18611869
}
18621870
return symbol;
18631871
}
@@ -16218,6 +16226,11 @@ namespace ts {
1621816226
return result && symbolName(result);
1621916227
}
1622016228

16229+
function getSuggestionForNonexistentModule(name: Identifier, targetModule: Symbol): string | undefined {
16230+
const suggestion = targetModule.exports && getSpellingSuggestionForName(idText(name), getExportsOfModuleAsArray(targetModule), SymbolFlags.ModuleMember);
16231+
return suggestion && symbolName(suggestion);
16232+
}
16233+
1622116234
/**
1622216235
* Given a name and a list of symbols whose names are *not* equal to the name, return a spelling suggestion if there is one that is close enough.
1622316236
* Names less than length 3 only check for case-insensitive equality, not levenshtein distance.

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2317,6 +2317,10 @@
23172317
"category": "Error",
23182318
"code": 2723
23192319
},
2320+
"Module '{0}' has no exported member '{1}'. Did you mean '{2}'?": {
2321+
"category": "Error",
2322+
"code": 2724
2323+
},
23202324
"Import declaration '{0}' is using private name '{1}'.": {
23212325
"category": "Error",
23222326
"code": 4000
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/conformance/es6/modules/b.ts(1,10): error TS2724: Module '"tests/cases/conformance/es6/modules/a"' has no exported member 'assertNevar'. Did you mean 'assertNever'?
2+
3+
4+
==== tests/cases/conformance/es6/modules/a.ts (0 errors) ====
5+
export function assertNever(x: never, msg: string) {
6+
throw new Error("Unexpected " + msg);
7+
}
8+
9+
==== tests/cases/conformance/es6/modules/b.ts (1 errors) ====
10+
import { assertNevar } from "./a";
11+
~~~~~~~~~~~
12+
!!! error TS2724: Module '"tests/cases/conformance/es6/modules/a"' has no exported member 'assertNevar'. Did you mean 'assertNever'?
13+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [tests/cases/conformance/es6/modules/exportSpellingSuggestion.ts] ////
2+
3+
//// [a.ts]
4+
export function assertNever(x: never, msg: string) {
5+
throw new Error("Unexpected " + msg);
6+
}
7+
8+
//// [b.ts]
9+
import { assertNevar } from "./a";
10+
11+
12+
//// [a.js]
13+
"use strict";
14+
exports.__esModule = true;
15+
function assertNever(x, msg) {
16+
throw new Error("Unexpected " + msg);
17+
}
18+
exports.assertNever = assertNever;
19+
//// [b.js]
20+
"use strict";
21+
exports.__esModule = true;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/es6/modules/a.ts ===
2+
export function assertNever(x: never, msg: string) {
3+
>assertNever : Symbol(assertNever, Decl(a.ts, 0, 0))
4+
>x : Symbol(x, Decl(a.ts, 0, 28))
5+
>msg : Symbol(msg, Decl(a.ts, 0, 37))
6+
7+
throw new Error("Unexpected " + msg);
8+
>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
9+
>msg : Symbol(msg, Decl(a.ts, 0, 37))
10+
}
11+
12+
=== tests/cases/conformance/es6/modules/b.ts ===
13+
import { assertNevar } from "./a";
14+
>assertNevar : Symbol(assertNevar, Decl(b.ts, 0, 8))
15+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/es6/modules/a.ts ===
2+
export function assertNever(x: never, msg: string) {
3+
>assertNever : (x: never, msg: string) => void
4+
>x : never
5+
>msg : string
6+
7+
throw new Error("Unexpected " + msg);
8+
>new Error("Unexpected " + msg) : Error
9+
>Error : ErrorConstructor
10+
>"Unexpected " + msg : string
11+
>"Unexpected " : "Unexpected "
12+
>msg : string
13+
}
14+
15+
=== tests/cases/conformance/es6/modules/b.ts ===
16+
import { assertNevar } from "./a";
17+
>assertNevar : any
18+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @filename: a.ts
2+
export function assertNever(x: never, msg: string) {
3+
throw new Error("Unexpected " + msg);
4+
}
5+
6+
// @filename: b.ts
7+
import { assertNevar } from "./a";

0 commit comments

Comments
 (0)