diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1ecf30690a0bc..dab6d45084f41 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2283,16 +2283,24 @@ namespace ts { } function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void { - const errorInfo = packageId && chainDiagnosticMessages( - /*details*/ undefined, - Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, - getMangledNameForScopedPackage(packageId.name)); + const errorInfo = packageId + ? chainDiagnosticMessages( + /*details*/ undefined, + typesPackageExists(packageId.name) + ? Diagnostics.If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_0 + : Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, + getMangledNameForScopedPackage(packageId.name)) + : undefined; errorOrSuggestion(isError, errorNode, chainDiagnosticMessages( errorInfo, Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type, moduleReference, resolvedFileName)); } + function typesPackageExists(packageName: string): boolean { + return host.getSourceFiles().some(sf => !!sf.resolvedModules && !!forEachEntry(sf.resolvedModules, r => + r && r.packageId && r.packageId.name === getTypesPackageName(packageName))); + } // An external module with an 'export =' declaration resolves to the target of the 'export =' declaration, // and an external module with no 'export =' declaration resolves to the module itself. diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 24b3031b8771e..7d08fd5caf120 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3636,7 +3636,7 @@ "category": "Message", "code": 6353 }, - + "Project '{0}' is up to date with .d.ts files from its dependencies": { "category": "Message", "code": 6354 @@ -3836,6 +3836,10 @@ "category": "Error", "code": 7039 }, + "If the '{0}' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/{0}`": { + "category": "Error", + "code": 7040 + }, "You cannot rename this element.": { "category": "Error", "code": 8000 diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 520c35a6b2ea2..46a686bb7498c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5752,6 +5752,7 @@ declare namespace ts { Enables_emit_interoperability_between_CommonJS_and_ES_Modules_via_creation_of_namespace_objects_for_all_imports_Implies_allowSyntheticDefaultImports: DiagnosticMessage; Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead: DiagnosticMessage; Mapped_object_type_implicitly_has_an_any_template_type: DiagnosticMessage; + If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_0: DiagnosticMessage; You_cannot_rename_this_element: DiagnosticMessage; You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: DiagnosticMessage; import_can_only_be_used_in_a_ts_file: DiagnosticMessage; diff --git a/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.errors.txt b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.errors.txt new file mode 100644 index 0000000000000..ef5997f8f5e08 --- /dev/null +++ b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.errors.txt @@ -0,0 +1,35 @@ +/a.ts(2,25): error TS7016: Could not find a declaration file for module 'foo/sub'. '/node_modules/foo/sub.js' implicitly has an 'any' type. + If the 'foo' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/foo` +/a.ts(3,25): error TS7016: Could not find a declaration file for module 'bar/sub'. '/node_modules/bar/sub.js' implicitly has an 'any' type. + Try `npm install @types/bar` if it exists or add a new declaration (.d.ts) file containing `declare module 'bar';` + + +==== /a.ts (2 errors) ==== + import * as foo from "foo"; + import * as fooSub from "foo/sub"; + ~~~~~~~~~ +!!! error TS7016: Could not find a declaration file for module 'foo/sub'. '/node_modules/foo/sub.js' implicitly has an 'any' type. +!!! error TS7016: If the 'foo' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/foo` + import * as barSub from "bar/sub"; + ~~~~~~~~~ +!!! error TS7016: Could not find a declaration file for module 'bar/sub'. '/node_modules/bar/sub.js' implicitly has an 'any' type. +!!! error TS7016: Try `npm install @types/bar` if it exists or add a new declaration (.d.ts) file containing `declare module 'bar';` + +==== /node_modules/@types/foo/index.d.ts (0 errors) ==== + export const foo: number; + +==== /node_modules/@types/foo/package.json (0 errors) ==== + { "name": "@types/foo", "version": "1.2.3" } + +==== /node_modules/foo/sub.js (0 errors) ==== + const x = 0; + +==== /node_modules/foo/package.json (0 errors) ==== + { "name": "foo", "version": "1.2.3" } + +==== /node_modules/bar/sub.js (0 errors) ==== + const x = 0; + +==== /node_modules/bar/package.json (0 errors) ==== + { "name": "bar", "version": "1.2.3" } + \ No newline at end of file diff --git a/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.js b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.js new file mode 100644 index 0000000000000..fe1a85730cd35 --- /dev/null +++ b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.js @@ -0,0 +1,29 @@ +//// [tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts] //// + +//// [index.d.ts] +export const foo: number; + +//// [package.json] +{ "name": "@types/foo", "version": "1.2.3" } + +//// [sub.js] +const x = 0; + +//// [package.json] +{ "name": "foo", "version": "1.2.3" } + +//// [sub.js] +const x = 0; + +//// [package.json] +{ "name": "bar", "version": "1.2.3" } + +//// [a.ts] +import * as foo from "foo"; +import * as fooSub from "foo/sub"; +import * as barSub from "bar/sub"; + + +//// [a.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.symbols b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.symbols new file mode 100644 index 0000000000000..59153d03f547f --- /dev/null +++ b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.symbols @@ -0,0 +1,14 @@ +=== /a.ts === +import * as foo from "foo"; +>foo : Symbol(foo, Decl(a.ts, 0, 6)) + +import * as fooSub from "foo/sub"; +>fooSub : Symbol(fooSub, Decl(a.ts, 1, 6)) + +import * as barSub from "bar/sub"; +>barSub : Symbol(barSub, Decl(a.ts, 2, 6)) + +=== /node_modules/@types/foo/index.d.ts === +export const foo: number; +>foo : Symbol(foo, Decl(index.d.ts, 0, 12)) + diff --git a/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.types b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.types new file mode 100644 index 0000000000000..9a6b7b7e69027 --- /dev/null +++ b/tests/baselines/reference/untypedModuleImport_noImplicitAny_typesForPackageExist.types @@ -0,0 +1,14 @@ +=== /a.ts === +import * as foo from "foo"; +>foo : typeof foo + +import * as fooSub from "foo/sub"; +>fooSub : any + +import * as barSub from "bar/sub"; +>barSub : any + +=== /node_modules/@types/foo/index.d.ts === +export const foo: number; +>foo : number + diff --git a/tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts b/tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts new file mode 100644 index 0000000000000..74e9da1080448 --- /dev/null +++ b/tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny_typesForPackageExist.ts @@ -0,0 +1,25 @@ +// @noImplicitReferences: true +// @strict: true + +// @Filename: /node_modules/@types/foo/index.d.ts +export const foo: number; + +// @Filename: /node_modules/@types/foo/package.json +{ "name": "@types/foo", "version": "1.2.3" } + +// @Filename: /node_modules/foo/sub.js +const x = 0; + +// @Filename: /node_modules/foo/package.json +{ "name": "foo", "version": "1.2.3" } + +// @Filename: /node_modules/bar/sub.js +const x = 0; + +// @Filename: /node_modules/bar/package.json +{ "name": "bar", "version": "1.2.3" } + +// @Filename: /a.ts +import * as foo from "foo"; +import * as fooSub from "foo/sub"; +import * as barSub from "bar/sub";