Skip to content

Commit 96f0122

Browse files
authored
fix(36909): wrong error message when trying to named-import an export (microsoft#36925)
1 parent 6d7539a commit 96f0122

39 files changed

+520
-18
lines changed

src/compiler/checker.ts

+35-12
Original file line numberDiff line numberDiff line change
@@ -2551,7 +2551,7 @@ namespace ts {
25512551
);
25522552
}
25532553
else {
2554-
reportNonExportedMember(name, declarationName, moduleSymbol, moduleName);
2554+
reportNonExportedMember(node, name, declarationName, moduleSymbol, moduleName);
25552555
}
25562556
}
25572557
}
@@ -2560,27 +2560,50 @@ namespace ts {
25602560
}
25612561
}
25622562

2563-
function reportNonExportedMember(name: Identifier, declarationName: string, moduleSymbol: Symbol, moduleName: string): void {
2563+
function reportNonExportedMember(node: ImportDeclaration | ExportDeclaration, name: Identifier, declarationName: string, moduleSymbol: Symbol, moduleName: string): void {
25642564
const localSymbol = moduleSymbol.valueDeclaration.locals?.get(name.escapedText);
25652565
const exports = moduleSymbol.exports;
2566-
25672566
if (localSymbol) {
2568-
const exportedSymbol = exports && !exports.has(InternalSymbolName.ExportEquals)
2569-
? find(symbolsToArray(exports), symbol => !!getSymbolIfSameReference(symbol, localSymbol))
2570-
: undefined;
2571-
const diagnostic = exportedSymbol
2572-
? error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, symbolToString(exportedSymbol))
2573-
: error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, moduleName, declarationName);
2567+
const exportedEqualsSymbol = exports?.get(InternalSymbolName.ExportEquals);
2568+
if (exportedEqualsSymbol) {
2569+
getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) ? reportInvalidImportEqualsExportMember(node, name, declarationName, moduleName) :
2570+
error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName);
2571+
}
2572+
else {
2573+
const exportedSymbol = exports ? find(symbolsToArray(exports), symbol => !!getSymbolIfSameReference(symbol, localSymbol)) : undefined;
2574+
const diagnostic = exportedSymbol ? error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, symbolToString(exportedSymbol)) :
2575+
error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, moduleName, declarationName);
25742576

2575-
addRelatedInfo(diagnostic,
2576-
...map(localSymbol.declarations, (decl, index) =>
2577-
createDiagnosticForNode(decl, index === 0 ? Diagnostics._0_is_declared_here : Diagnostics.and_here, declarationName)));
2577+
addRelatedInfo(diagnostic,
2578+
...map(localSymbol.declarations, (decl, index) =>
2579+
createDiagnosticForNode(decl, index === 0 ? Diagnostics._0_is_declared_here : Diagnostics.and_here, declarationName)));
2580+
}
25782581
}
25792582
else {
25802583
error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName);
25812584
}
25822585
}
25832586

2587+
function reportInvalidImportEqualsExportMember(node: ImportDeclaration | ExportDeclaration, name: Identifier, declarationName: string, moduleName: string) {
2588+
if (moduleKind >= ModuleKind.ES2015) {
2589+
const message = compilerOptions.esModuleInterop ? Diagnostics._0_can_only_be_imported_by_using_a_default_import :
2590+
Diagnostics._0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import;
2591+
error(name, message, declarationName);
2592+
}
2593+
else {
2594+
if (isInJSFile(node)) {
2595+
const message = compilerOptions.esModuleInterop ? Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_using_a_default_import :
2596+
Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import;
2597+
error(name, message, declarationName);
2598+
}
2599+
else {
2600+
const message = compilerOptions.esModuleInterop ? Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import :
2601+
Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import;
2602+
error(name, message, declarationName, declarationName, moduleName);
2603+
}
2604+
}
2605+
}
2606+
25842607
function getTargetOfImportSpecifier(node: ImportSpecifier, dontResolveAlias: boolean): Symbol | undefined {
25852608
const resolved = getExternalModuleMember(node.parent.parent.parent, node, dontResolveAlias);
25862609
markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false);

src/compiler/diagnosticMessages.json

+24
Original file line numberDiff line numberDiff line change
@@ -2321,6 +2321,22 @@
23212321
"category": "Error",
23222322
"code": 2594
23232323
},
2324+
"'{0}' can only be imported by using a default import.": {
2325+
"category": "Error",
2326+
"code": 2595
2327+
},
2328+
"'{0}' can only be imported by turning on the 'esModuleInterop' flag and using a default import.": {
2329+
"category": "Error",
2330+
"code": 2596
2331+
},
2332+
"'{0}' can only be imported by using a 'require' call or by using a default import.": {
2333+
"category": "Error",
2334+
"code": 2597
2335+
},
2336+
"'{0}' can only be imported by using a 'require' call or by turning on the 'esModuleInterop' flag and using a default import.": {
2337+
"category": "Error",
2338+
"code": 2598
2339+
},
23242340
"JSX element attributes type '{0}' may not be a union type.": {
23252341
"category": "Error",
23262342
"code": 2600
@@ -2385,6 +2401,14 @@
23852401
"category": "Error",
23862402
"code": 2615
23872403
},
2404+
"'{0}' can only be imported by using 'import {1} = require({2})' or a default import.": {
2405+
"category": "Error",
2406+
"code": 2616
2407+
},
2408+
"'{0}' can only be imported by using 'import {1} = require({2})' or by turning on the 'esModuleInterop' flag and using a default import.": {
2409+
"category": "Error",
2410+
"code": 2617
2411+
},
23882412

23892413
"Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": {
23902414
"category": "Error",
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(1,10): error TS2459: Module '"./es6ImportNamedImportNoNamedExports_0"' declares 'a' locally, but it is not exported.
2-
tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(2,10): error TS2459: Module '"./es6ImportNamedImportNoNamedExports_0"' declares 'a' locally, but it is not exported.
1+
tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(1,10): error TS2617: 'a' can only be imported by using 'import a = require("./es6ImportNamedImportNoNamedExports_0")' or by turning on the 'esModuleInterop' flag and using a default import.
2+
tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(2,10): error TS2617: 'a' can only be imported by using 'import a = require("./es6ImportNamedImportNoNamedExports_0")' or by turning on the 'esModuleInterop' flag and using a default import.
33

44

55
==== tests/cases/compiler/es6ImportNamedImportNoNamedExports_0.ts (0 errors) ====
@@ -9,9 +9,7 @@ tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(2,10): error TS2459
99
==== tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts (2 errors) ====
1010
import { a } from "./es6ImportNamedImportNoNamedExports_0";
1111
~
12-
!!! error TS2459: Module '"./es6ImportNamedImportNoNamedExports_0"' declares 'a' locally, but it is not exported.
13-
!!! related TS2728 tests/cases/compiler/es6ImportNamedImportNoNamedExports_0.ts:1:5: 'a' is declared here.
12+
!!! error TS2617: 'a' can only be imported by using 'import a = require("./es6ImportNamedImportNoNamedExports_0")' or by turning on the 'esModuleInterop' flag and using a default import.
1413
import { a as x } from "./es6ImportNamedImportNoNamedExports_0";
1514
~
16-
!!! error TS2459: Module '"./es6ImportNamedImportNoNamedExports_0"' declares 'a' locally, but it is not exported.
17-
!!! related TS2728 tests/cases/compiler/es6ImportNamedImportNoNamedExports_0.ts:1:5: 'a' is declared here.
15+
!!! error TS2617: 'a' can only be imported by using 'import a = require("./es6ImportNamedImportNoNamedExports_0")' or by turning on the 'esModuleInterop' flag and using a default import.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/a.ts(2,1): error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.
2+
tests/cases/compiler/b.js(1,10): error TS2596: 'Foo' can only be imported by turning on the 'esModuleInterop' flag and using a default import.
3+
tests/cases/compiler/b.js(1,21): error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'allowSyntheticDefaultImports' flag and referencing its default export.
4+
5+
6+
==== tests/cases/compiler/a.ts (1 errors) ====
7+
class Foo {}
8+
export = Foo;
9+
~~~~~~~~~~~~~
10+
!!! error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.
11+
12+
==== tests/cases/compiler/b.js (2 errors) ====
13+
import { Foo } from './a';
14+
~~~
15+
!!! error TS2596: 'Foo' can only be imported by turning on the 'esModuleInterop' flag and using a default import.
16+
~~~~~
17+
!!! error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'allowSyntheticDefaultImports' flag and referencing its default export.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
4+
5+
export = Foo;
6+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
7+
8+
=== tests/cases/compiler/b.js ===
9+
import { Foo } from './a';
10+
>Foo : Symbol(Foo, Decl(b.js, 0, 8))
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Foo
4+
5+
export = Foo;
6+
>Foo : Foo
7+
8+
=== tests/cases/compiler/b.js ===
9+
import { Foo } from './a';
10+
>Foo : any
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/a.ts(2,1): error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.
2+
tests/cases/compiler/b.js(1,10): error TS2595: 'Foo' can only be imported by using a default import.
3+
tests/cases/compiler/b.js(1,21): error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'allowSyntheticDefaultImports' flag and referencing its default export.
4+
5+
6+
==== tests/cases/compiler/a.ts (1 errors) ====
7+
class Foo {}
8+
export = Foo;
9+
~~~~~~~~~~~~~
10+
!!! error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.
11+
12+
==== tests/cases/compiler/b.js (2 errors) ====
13+
import { Foo } from './a';
14+
~~~
15+
!!! error TS2595: 'Foo' can only be imported by using a default import.
16+
~~~~~
17+
!!! error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'allowSyntheticDefaultImports' flag and referencing its default export.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
4+
5+
export = Foo;
6+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
7+
8+
=== tests/cases/compiler/b.js ===
9+
import { Foo } from './a';
10+
>Foo : Symbol(Foo, Decl(b.js, 0, 8))
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Foo
4+
5+
export = Foo;
6+
>Foo : Foo
7+
8+
=== tests/cases/compiler/b.js ===
9+
import { Foo } from './a';
10+
>Foo : any
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/compiler/b.ts(1,10): error TS2617: 'Foo' can only be imported by using 'import Foo = require("./a")' or by turning on the 'esModuleInterop' flag and using a default import.
2+
tests/cases/compiler/b.ts(1,21): error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'esModuleInterop' flag and referencing its default export.
3+
4+
5+
==== tests/cases/compiler/a.ts (0 errors) ====
6+
class Foo {}
7+
export = Foo;
8+
9+
==== tests/cases/compiler/b.ts (2 errors) ====
10+
import { Foo } from './a';
11+
~~~
12+
!!! error TS2617: 'Foo' can only be imported by using 'import Foo = require("./a")' or by turning on the 'esModuleInterop' flag and using a default import.
13+
~~~~~
14+
!!! error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'esModuleInterop' flag and referencing its default export.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [tests/cases/compiler/importNonExportedMember4.ts] ////
2+
3+
//// [a.ts]
4+
class Foo {}
5+
export = Foo;
6+
7+
//// [b.ts]
8+
import { Foo } from './a';
9+
10+
//// [a.js]
11+
"use strict";
12+
var Foo = /** @class */ (function () {
13+
function Foo() {
14+
}
15+
return Foo;
16+
}());
17+
module.exports = Foo;
18+
//// [b.js]
19+
"use strict";
20+
exports.__esModule = true;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
4+
5+
export = Foo;
6+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
7+
8+
=== tests/cases/compiler/b.ts ===
9+
import { Foo } from './a';
10+
>Foo : Symbol(Foo, Decl(b.ts, 0, 8))
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Foo
4+
5+
export = Foo;
6+
>Foo : Foo
7+
8+
=== tests/cases/compiler/b.ts ===
9+
import { Foo } from './a';
10+
>Foo : any
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/compiler/b.ts(1,10): error TS2616: 'Foo' can only be imported by using 'import Foo = require("./a")' or a default import.
2+
tests/cases/compiler/b.ts(1,21): error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'esModuleInterop' flag and referencing its default export.
3+
4+
5+
==== tests/cases/compiler/a.ts (0 errors) ====
6+
class Foo {}
7+
export = Foo;
8+
9+
==== tests/cases/compiler/b.ts (2 errors) ====
10+
import { Foo } from './a';
11+
~~~
12+
!!! error TS2616: 'Foo' can only be imported by using 'import Foo = require("./a")' or a default import.
13+
~~~~~
14+
!!! error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'esModuleInterop' flag and referencing its default export.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [tests/cases/compiler/importNonExportedMember5.ts] ////
2+
3+
//// [a.ts]
4+
class Foo {}
5+
export = Foo;
6+
7+
//// [b.ts]
8+
import { Foo } from './a';
9+
10+
//// [a.js]
11+
"use strict";
12+
var Foo = /** @class */ (function () {
13+
function Foo() {
14+
}
15+
return Foo;
16+
}());
17+
module.exports = Foo;
18+
//// [b.js]
19+
"use strict";
20+
exports.__esModule = true;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
4+
5+
export = Foo;
6+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
7+
8+
=== tests/cases/compiler/b.ts ===
9+
import { Foo } from './a';
10+
>Foo : Symbol(Foo, Decl(b.ts, 0, 8))
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Foo
4+
5+
export = Foo;
6+
>Foo : Foo
7+
8+
=== tests/cases/compiler/b.ts ===
9+
import { Foo } from './a';
10+
>Foo : any
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/a.ts(2,1): error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.
2+
tests/cases/compiler/b.ts(1,10): error TS2596: 'Foo' can only be imported by turning on the 'esModuleInterop' flag and using a default import.
3+
tests/cases/compiler/b.ts(1,21): error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'allowSyntheticDefaultImports' flag and referencing its default export.
4+
5+
6+
==== tests/cases/compiler/a.ts (1 errors) ====
7+
class Foo {}
8+
export = Foo;
9+
~~~~~~~~~~~~~
10+
!!! error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.
11+
12+
==== tests/cases/compiler/b.ts (2 errors) ====
13+
import { Foo } from './a';
14+
~~~
15+
!!! error TS2596: 'Foo' can only be imported by turning on the 'esModuleInterop' flag and using a default import.
16+
~~~~~
17+
!!! error TS2497: This module can only be referenced with ECMAScript imports/exports by turning on the 'allowSyntheticDefaultImports' flag and referencing its default export.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [tests/cases/compiler/importNonExportedMember6.ts] ////
2+
3+
//// [a.ts]
4+
class Foo {}
5+
export = Foo;
6+
7+
//// [b.ts]
8+
import { Foo } from './a';
9+
10+
//// [a.js]
11+
var Foo = /** @class */ (function () {
12+
function Foo() {
13+
}
14+
return Foo;
15+
}());
16+
//// [b.js]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
4+
5+
export = Foo;
6+
>Foo : Symbol(Foo, Decl(a.ts, 0, 0))
7+
8+
=== tests/cases/compiler/b.ts ===
9+
import { Foo } from './a';
10+
>Foo : Symbol(Foo, Decl(b.ts, 0, 8))
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/a.ts ===
2+
class Foo {}
3+
>Foo : Foo
4+
5+
export = Foo;
6+
>Foo : Foo
7+
8+
=== tests/cases/compiler/b.ts ===
9+
import { Foo } from './a';
10+
>Foo : any
11+

0 commit comments

Comments
 (0)