Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions tsc/internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -15422,6 +15422,25 @@ func (c *Checker) getCannotResolveModuleNameErrorForSpecificModule(moduleName *a
return nil
}

// Returns a more specific error when a failed non-relative module import matches a global
// namespace declaration, e.g. `declare module foo { }`, which declares a namespace rather
// than an ambient module. See https://github.com/microsoft/TypeScript/issues/23185.
func (c *Checker) getCannotResolveModuleNameErrorForGlobalNamespace(moduleReference string) *diagnostics.Message {
if tspath.IsExternalModuleNameRelative(moduleReference) {
return nil
}
symbol := c.getGlobalSymbol(moduleReference, ast.SymbolFlagsModule, nil /*diagnostic*/)
if symbol == nil {
return nil
}
for _, declaration := range symbol.Declarations() {
if ast.IsModuleDeclaration(declaration) && !ast.IsStringLiteral(declaration.Name()) {
return diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations_Did_you_mean_to_use_the_global_namespace_0_If_you_meant_to_declare_an_ambient_module_the_name_must_be_quoted_Colon_declare_module_0
}
}
return nil
}

func (c *Checker) resolveExternalModuleNameWorker(location *ast.Node, moduleReferenceExpression *ast.Node, moduleNotFoundError *diagnostics.Message, ignoreErrors bool, isForAugmentation bool, importAttributesType *Type) *ast.Symbol {
if ast.IsStringLiteralLike(moduleReferenceExpression) {
if ast.IsSourcePhaseImport(moduleReferenceExpression.Parent) {
Expand Down Expand Up @@ -15716,6 +15735,11 @@ func (c *Checker) resolveExternalModule(
}

if moduleNotFoundError != nil {
if moduleNotFoundError == diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations {
if betterError := c.getCannotResolveModuleNameErrorForGlobalNamespace(moduleReference); betterError != nil {
moduleNotFoundError = betterError
Comment thread
mahesh-desu marked this conversation as resolved.
}
}
// See if this was possibly a projectReference redirect
if resolvedModule.IsResolved() {
redirect := c.program.GetProjectReferenceFromSource(
Expand Down Expand Up @@ -15873,6 +15897,13 @@ func (c *Checker) errorOnImplicitAnyModule(isError bool, errorNode *ast.Node, mo
return
}

if isError {
if globalNamespaceError := c.getCannotResolveModuleNameErrorForGlobalNamespace(moduleReference); globalNamespaceError != nil {
c.error(errorNode, globalNamespaceError, moduleReference)
return
}
}

var errorInfo *ast.Diagnostic
if !tspath.IsExternalModuleNameRelative(moduleReference) && resolvedModule.PackageId.Name != "" {
errorInfo = c.createModuleNotFoundChain(resolvedModule, errorNode, moduleReference, mode, resolvedModule.PackageId.Name)
Expand Down
1 change: 1 addition & 0 deletions tsc/internal/diagnostics/diagnosticMessages.generated.json
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,7 @@
"Source_phase_imports_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls_18115": "Source phase imports are not allowed on statements that compile to CommonJS 'require' calls.",
"This_initializer_has_a_Symbol_asyncDispose_method_Did_you_mean_to_use_await_using_18116": "This initializer has a '[Symbol.asyncDispose]()' method. Did you mean to use 'await using'?",
"A_deferred_import_must_specify_a_namespace_binding_18117": "A deferred import must specify a namespace binding.",
"Cannot_find_module_0_or_its_corresponding_type_declarations_Did_you_mean_to_use_the_global_namespace_18118": "Cannot find module '{0}' or its corresponding type declarations. Did you mean to use the global namespace '{0}'? If you meant to declare an ambient module, the name must be quoted: `declare module '{0}';`.",
"nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler_69010": "`nodenext` if `module` is `nodenext`; `node16` if `module` is `node16` or `node18`; otherwise, `bundler`.",
"File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module_80001": "File is a CommonJS module; it may be converted to an ES module.",
"This_constructor_function_may_be_converted_to_a_class_declaration_80002": "This constructor function may be converted to a class declaration.",
Expand Down
4 changes: 4 additions & 0 deletions tsc/internal/diagnostics/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -8923,5 +8923,9 @@
"A deferred import must specify a namespace binding.": {
"category": "Error",
"code": 18117
},
"Cannot find module '{0}' or its corresponding type declarations. Did you mean to use the global namespace '{0}'? If you meant to declare an ambient module, the name must be quoted: `declare module '{0}';`.": {
"category": "Error",
"code": 18118
}
}
3 changes: 3 additions & 0 deletions tsc/internal/diagnostics/diagnostics_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
globals.d.ts(1,16): error TS1540: A 'namespace' declaration should not be declared using the 'module' keyword. Please use the 'namespace' keyword instead.
globals.d.ts(4,16): error TS1540: A 'namespace' declaration should not be declared using the 'module' keyword. Please use the 'namespace' keyword instead.
main.ts(2,27): error TS18118: Cannot find module 'messageformat' or its corresponding type declarations. Did you mean to use the global namespace 'messageformat'? If you meant to declare an ambient module, the name must be quoted: `declare module 'messageformat';`.
main.ts(3,19): error TS18118: Cannot find module 'otherlib' or its corresponding type declarations. Did you mean to use the global namespace 'otherlib'? If you meant to declare an ambient module, the name must be quoted: `declare module 'otherlib';`.
main.ts(4,27): error TS2307: Cannot find module 'not-declared-globally' or its corresponding type declarations.


==== main.ts (3 errors) ====
/// <reference path="globals.d.ts" />
import MessageFormat from "messageformat";
~~~~~~~~~~~~~~~
!!! error TS18118: Cannot find module 'messageformat' or its corresponding type declarations. Did you mean to use the global namespace 'messageformat'? If you meant to declare an ambient module, the name must be quoted: `declare module 'messageformat';`.
import Other from "otherlib";
~~~~~~~~~~
!!! error TS18118: Cannot find module 'otherlib' or its corresponding type declarations. Did you mean to use the global namespace 'otherlib'? If you meant to declare an ambient module, the name must be quoted: `declare module 'otherlib';`.
import { something } from "not-declared-globally";
~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'not-declared-globally' or its corresponding type declarations.

==== /node_modules/messageformat/package.json (0 errors) ====
{
"name": "messageformat",
"version": "1.0.0",
"main": "lib/messageformat.js"
}

==== /node_modules/messageformat/lib/messageformat.js (0 errors) ====
module.exports = function messageformat() {};

==== globals.d.ts (2 errors) ====
declare module messageformat {
~~~~~~~~~~~~~
!!! error TS1540: A 'namespace' declaration should not be declared using the 'module' keyword. Please use the 'namespace' keyword instead.
export type Msg = (params: {}) => string;
}
declare module otherlib {
~~~~~~~~
!!! error TS1540: A 'namespace' declaration should not be declared using the 'module' keyword. Please use the 'namespace' keyword instead.
export type Other = string;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//// [tests/cases/compiler/cannotFindModuleWithGlobalNamespace.ts] ////

//// [package.json]
{
"name": "messageformat",
"version": "1.0.0",
"main": "lib/messageformat.js"
}

//// [messageformat.js]
module.exports = function messageformat() {};

//// [globals.d.ts]
declare module messageformat {
export type Msg = (params: {}) => string;
}
declare module otherlib {
export type Other = string;
}

//// [main.ts]
/// <reference path="globals.d.ts" />
import MessageFormat from "messageformat";
import Other from "otherlib";
import { something } from "not-declared-globally";


//// [main.js]
export {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//// [tests/cases/compiler/cannotFindModuleWithGlobalNamespace.ts] ////

=== main.ts ===
/// <reference path="globals.d.ts" />
import MessageFormat from "messageformat";
>MessageFormat : Symbol(MessageFormat, Decl(main.ts, 1, 6))

import Other from "otherlib";
>Other : Symbol(Other, Decl(main.ts, 2, 6))

import { something } from "not-declared-globally";
>something : Symbol(something, Decl(main.ts, 3, 8))

=== globals.d.ts ===
declare module messageformat {
>messageformat : Symbol(messageformat, Decl(globals.d.ts, 0, 0))

export type Msg = (params: {}) => string;
>Msg : Symbol(Msg, Decl(globals.d.ts, 0, 30))
>params : Symbol(params, Decl(globals.d.ts, 1, 23))
}
declare module otherlib {
>otherlib : Symbol(otherlib, Decl(globals.d.ts, 2, 1))

export type Other = string;
>Other : Symbol(Other, Decl(globals.d.ts, 3, 25))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//// [tests/cases/compiler/cannotFindModuleWithGlobalNamespace.ts] ////

=== main.ts ===
/// <reference path="globals.d.ts" />
import MessageFormat from "messageformat";
>MessageFormat : any

import Other from "otherlib";
>Other : any

import { something } from "not-declared-globally";
>something : any

=== globals.d.ts ===
declare module messageformat {
export type Msg = (params: {}) => string;
>Msg : Msg
>params : {}
}
declare module otherlib {
export type Other = string;
>Other : string
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// @strict: true
// @noImplicitReferences: true

// @Filename: /node_modules/messageformat/package.json
{
"name": "messageformat",
"version": "1.0.0",
"main": "lib/messageformat.js"
}

// @Filename: /node_modules/messageformat/lib/messageformat.js
module.exports = function messageformat() {};

// @Filename: globals.d.ts
declare module messageformat {
export type Msg = (params: {}) => string;
}
declare module otherlib {
export type Other = string;
}

// @Filename: main.ts
/// <reference path="globals.d.ts" />
import MessageFormat from "messageformat";
import Other from "otherlib";
import { something } from "not-declared-globally";