diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index de07b62ac566f..23193c335c514 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2346,7 +2346,7 @@ namespace ts { } } else { - if (moduleSymbol.exports && moduleSymbol.exports.has(InternalSymbolName.Default)) { + if (moduleSymbol.exports?.has(InternalSymbolName.Default)) { error( name, Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_to_use_import_1_from_0_instead, @@ -2355,7 +2355,7 @@ namespace ts { ); } else { - error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); + reportNonExportedMember(name, declarationName, moduleSymbol, moduleName); } } } @@ -2364,6 +2364,27 @@ namespace ts { } } + function reportNonExportedMember(name: Identifier, declarationName: string, moduleSymbol: Symbol, moduleName: string): void { + const localSymbol = moduleSymbol.valueDeclaration.locals?.get(name.escapedText); + const exports = moduleSymbol.exports; + + if (localSymbol) { + const exportedSymbol = exports && !exports.has(InternalSymbolName.ExportEquals) + ? find(symbolsToArray(exports), symbol => !!getSymbolIfSameReference(symbol, localSymbol)) + : undefined; + const diagnostic = exportedSymbol + ? error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, symbolToString(exportedSymbol)) + : error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, moduleName, declarationName); + + addRelatedInfo(diagnostic, + createDiagnosticForNode(localSymbol.valueDeclaration, Diagnostics._0_is_declared_here, declarationName) + ); + } + else { + error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); + } + } + function getTargetOfImportSpecifier(node: ImportSpecifier, dontResolveAlias: boolean): Symbol | undefined { const resolved = getExternalModuleMember(node.parent.parent.parent, node, dontResolveAlias); if (resolved && node.parent.parent.isTypeOnly) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index bd4d56c2a9c7e..46efc73c65f9c 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1765,6 +1765,14 @@ "category": "Error", "code": 2458 }, + "Module '{0}' declares '{1}' locally, but it is not exported.": { + "category": "Error", + "code": 2459 + }, + "Module '{0}' declares '{1}' locally, but it is exported as '{2}'.": { + "category": "Error", + "code": 2460 + }, "Type '{0}' is not an array type.": { "category": "Error", "code": 2461 diff --git a/tests/baselines/reference/es6ImportNamedImportNoNamedExports.errors.txt b/tests/baselines/reference/es6ImportNamedImportNoNamedExports.errors.txt index aed703af0fc25..1219ff6255186 100644 --- a/tests/baselines/reference/es6ImportNamedImportNoNamedExports.errors.txt +++ b/tests/baselines/reference/es6ImportNamedImportNoNamedExports.errors.txt @@ -1,5 +1,5 @@ -tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(1,10): error TS2305: Module '"./es6ImportNamedImportNoNamedExports_0"' has no exported member 'a'. -tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(2,10): error TS2305: Module '"./es6ImportNamedImportNoNamedExports_0"' has no exported member 'a'. +tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(1,10): error TS2459: Module '"./es6ImportNamedImportNoNamedExports_0"' declares 'a' locally, but it is not exported. +tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(2,10): error TS2459: Module '"./es6ImportNamedImportNoNamedExports_0"' declares 'a' locally, but it is not exported. ==== tests/cases/compiler/es6ImportNamedImportNoNamedExports_0.ts (0 errors) ==== @@ -9,7 +9,9 @@ tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts(2,10): error TS2305 ==== tests/cases/compiler/es6ImportNamedImportNoNamedExports_1.ts (2 errors) ==== import { a } from "./es6ImportNamedImportNoNamedExports_0"; ~ -!!! error TS2305: Module '"./es6ImportNamedImportNoNamedExports_0"' has no exported member 'a'. +!!! error TS2459: Module '"./es6ImportNamedImportNoNamedExports_0"' declares 'a' locally, but it is not exported. +!!! related TS2728 tests/cases/compiler/es6ImportNamedImportNoNamedExports_0.ts:1:5: 'a' is declared here. import { a as x } from "./es6ImportNamedImportNoNamedExports_0"; ~ -!!! error TS2305: Module '"./es6ImportNamedImportNoNamedExports_0"' has no exported member 'a'. \ No newline at end of file +!!! error TS2459: Module '"./es6ImportNamedImportNoNamedExports_0"' declares 'a' locally, but it is not exported. +!!! related TS2728 tests/cases/compiler/es6ImportNamedImportNoNamedExports_0.ts:1:5: 'a' is declared here. \ No newline at end of file diff --git a/tests/baselines/reference/importNonExportedMember.errors.txt b/tests/baselines/reference/importNonExportedMember.errors.txt new file mode 100644 index 0000000000000..abb9d6281b360 --- /dev/null +++ b/tests/baselines/reference/importNonExportedMember.errors.txt @@ -0,0 +1,14 @@ +tests/cases/compiler/b.ts(1,15): error TS2460: Module '"./a"' declares 'bar' locally, but it is exported as 'baz'. + + +==== tests/cases/compiler/a.ts (0 errors) ==== + declare function foo(): any + declare function bar(): any; + export { foo, bar as baz }; + +==== tests/cases/compiler/b.ts (1 errors) ==== + import { foo, bar } from "./a"; + ~~~ +!!! error TS2460: Module '"./a"' declares 'bar' locally, but it is exported as 'baz'. +!!! related TS2728 tests/cases/compiler/a.ts:2:18: 'bar' is declared here. + \ No newline at end of file diff --git a/tests/baselines/reference/importNonExportedMember.js b/tests/baselines/reference/importNonExportedMember.js new file mode 100644 index 0000000000000..3aff52e723d92 --- /dev/null +++ b/tests/baselines/reference/importNonExportedMember.js @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/importNonExportedMember.ts] //// + +//// [a.ts] +declare function foo(): any +declare function bar(): any; +export { foo, bar as baz }; + +//// [b.ts] +import { foo, bar } from "./a"; + + +//// [a.js] +"use strict"; +exports.__esModule = true; +//// [b.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/importNonExportedMember.symbols b/tests/baselines/reference/importNonExportedMember.symbols new file mode 100644 index 0000000000000..2c5d85bf48a65 --- /dev/null +++ b/tests/baselines/reference/importNonExportedMember.symbols @@ -0,0 +1,17 @@ +=== tests/cases/compiler/a.ts === +declare function foo(): any +>foo : Symbol(foo, Decl(a.ts, 0, 0)) + +declare function bar(): any; +>bar : Symbol(bar, Decl(a.ts, 0, 27)) + +export { foo, bar as baz }; +>foo : Symbol(foo, Decl(a.ts, 2, 8)) +>bar : Symbol(bar, Decl(a.ts, 0, 27)) +>baz : Symbol(baz, Decl(a.ts, 2, 13)) + +=== tests/cases/compiler/b.ts === +import { foo, bar } from "./a"; +>foo : Symbol(foo, Decl(b.ts, 0, 8)) +>bar : Symbol(bar, Decl(b.ts, 0, 13)) + diff --git a/tests/baselines/reference/importNonExportedMember.types b/tests/baselines/reference/importNonExportedMember.types new file mode 100644 index 0000000000000..dbf49aeb96c93 --- /dev/null +++ b/tests/baselines/reference/importNonExportedMember.types @@ -0,0 +1,17 @@ +=== tests/cases/compiler/a.ts === +declare function foo(): any +>foo : () => any + +declare function bar(): any; +>bar : () => any + +export { foo, bar as baz }; +>foo : () => any +>bar : () => any +>baz : () => any + +=== tests/cases/compiler/b.ts === +import { foo, bar } from "./a"; +>foo : () => any +>bar : any + diff --git a/tests/baselines/reference/importNonExportedMember1.errors.txt b/tests/baselines/reference/importNonExportedMember1.errors.txt new file mode 100644 index 0000000000000..80cae4d278425 --- /dev/null +++ b/tests/baselines/reference/importNonExportedMember1.errors.txt @@ -0,0 +1,14 @@ +tests/cases/compiler/b.ts(1,10): error TS2459: Module '"./a"' declares 'bar' locally, but it is not exported. + + +==== tests/cases/compiler/a.ts (0 errors) ==== + declare function foo(): any + declare function bar(): any; + export { foo }; + +==== tests/cases/compiler/b.ts (1 errors) ==== + import { bar } from "./a"; + ~~~ +!!! error TS2459: Module '"./a"' declares 'bar' locally, but it is not exported. +!!! related TS2728 tests/cases/compiler/a.ts:2:18: 'bar' is declared here. + \ No newline at end of file diff --git a/tests/baselines/reference/importNonExportedMember1.js b/tests/baselines/reference/importNonExportedMember1.js new file mode 100644 index 0000000000000..5309080c4a997 --- /dev/null +++ b/tests/baselines/reference/importNonExportedMember1.js @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/importNonExportedMember1.ts] //// + +//// [a.ts] +declare function foo(): any +declare function bar(): any; +export { foo }; + +//// [b.ts] +import { bar } from "./a"; + + +//// [a.js] +"use strict"; +exports.__esModule = true; +//// [b.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/importNonExportedMember1.symbols b/tests/baselines/reference/importNonExportedMember1.symbols new file mode 100644 index 0000000000000..1fb7b5418c55e --- /dev/null +++ b/tests/baselines/reference/importNonExportedMember1.symbols @@ -0,0 +1,14 @@ +=== tests/cases/compiler/a.ts === +declare function foo(): any +>foo : Symbol(foo, Decl(a.ts, 0, 0)) + +declare function bar(): any; +>bar : Symbol(bar, Decl(a.ts, 0, 27)) + +export { foo }; +>foo : Symbol(foo, Decl(a.ts, 2, 8)) + +=== tests/cases/compiler/b.ts === +import { bar } from "./a"; +>bar : Symbol(bar, Decl(b.ts, 0, 8)) + diff --git a/tests/baselines/reference/importNonExportedMember1.types b/tests/baselines/reference/importNonExportedMember1.types new file mode 100644 index 0000000000000..e4ec51b4b7676 --- /dev/null +++ b/tests/baselines/reference/importNonExportedMember1.types @@ -0,0 +1,14 @@ +=== tests/cases/compiler/a.ts === +declare function foo(): any +>foo : () => any + +declare function bar(): any; +>bar : () => any + +export { foo }; +>foo : () => any + +=== tests/cases/compiler/b.ts === +import { bar } from "./a"; +>bar : any + diff --git a/tests/cases/compiler/importNonExportedMember.ts b/tests/cases/compiler/importNonExportedMember.ts new file mode 100644 index 0000000000000..103210edc8321 --- /dev/null +++ b/tests/cases/compiler/importNonExportedMember.ts @@ -0,0 +1,7 @@ +// @filename: a.ts +declare function foo(): any +declare function bar(): any; +export { foo, bar as baz }; + +// @filename: b.ts +import { foo, bar } from "./a"; diff --git a/tests/cases/compiler/importNonExportedMember1.ts b/tests/cases/compiler/importNonExportedMember1.ts new file mode 100644 index 0000000000000..e3242ce60043d --- /dev/null +++ b/tests/cases/compiler/importNonExportedMember1.ts @@ -0,0 +1,7 @@ +// @filename: a.ts +declare function foo(): any +declare function bar(): any; +export { foo }; + +// @filename: b.ts +import { bar } from "./a";