diff --git a/src/services/completions.ts b/src/services/completions.ts
index f0ad156956d82..e7b1a8e86bdd4 100644
--- a/src/services/completions.ts
+++ b/src/services/completions.ts
@@ -855,6 +855,7 @@ namespace ts.Completions {
host: LanguageServiceHost
): CompletionData | Request | undefined {
const typeChecker = program.getTypeChecker();
+ const compilerOptions = program.getCompilerOptions();
let start = timestamp();
let currentToken = getTokenAtPosition(sourceFile, position); // TODO: GH#15853
@@ -1519,7 +1520,22 @@ namespace ts.Completions {
return false;
}
- symbol = skipAlias(symbol, typeChecker);
+ // External modules can have global export declarations that will be
+ // available as global keywords in all scopes. But if the external module
+ // already has an explicit export and user only wants to user explicit
+ // module imports then the global keywords will be filtered out so auto
+ // import suggestions will win in the completion
+ const symbolOrigin = skipAlias(symbol, typeChecker);
+ // We only want to filter out the global keywords
+ // Auto Imports are not available for scripts so this conditional is always false
+ if (!!sourceFile.externalModuleIndicator
+ && !compilerOptions.allowUmdGlobalAccess
+ && symbolToSortTextMap[getSymbolId(symbol)] === SortText.GlobalsOrKeywords
+ && symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.AutoImportSuggestions) {
+ return false;
+ }
+ // Continue with origin symbol
+ symbol = symbolOrigin;
// import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace)
if (isInRightSideOfInternalImportEqualsDeclaration(location)) {
diff --git a/tests/cases/fourslash/completionsImport_umdModules1_globalAccess.ts b/tests/cases/fourslash/completionsImport_umdModules1_globalAccess.ts
new file mode 100644
index 0000000000000..3e2225ec8c12a
--- /dev/null
+++ b/tests/cases/fourslash/completionsImport_umdModules1_globalAccess.ts
@@ -0,0 +1,33 @@
+///
+
+// @filename: /package.json
+//// { "dependencies": { "@types/classnames": "*" } }
+
+// @filename: /tsconfig.json
+//// { "compilerOptions": { "allowUmdGlobalAccess": true } }
+
+// @filename: /node_modules/@types/classnames/package.json
+//// { "name": "@types/classnames", "types": "index.d.ts" }
+
+// @filename: /node_modules/@types/classnames/index.d.ts
+//// declare const classNames: () => string;
+//// export = classNames;
+//// export as namespace classNames;
+
+// @filename: /SomeReactComponent.tsx
+//// import * as React from 'react';
+////
+//// const el1 =
foo
;
+
+goTo.marker("1");
+
+verify.completions({
+ includes: [{
+ name: "classNames",
+ hasAction: undefined, // Asserts to have no actions
+ sortText: completion.SortText.GlobalsOrKeywords,
+ }],
+ preferences: {
+ includeCompletionsForModuleExports: true,
+ }
+});
diff --git a/tests/cases/fourslash/completionsImport_umdModules2_moduleExports.ts b/tests/cases/fourslash/completionsImport_umdModules2_moduleExports.ts
new file mode 100644
index 0000000000000..56db8733cbc49
--- /dev/null
+++ b/tests/cases/fourslash/completionsImport_umdModules2_moduleExports.ts
@@ -0,0 +1,34 @@
+///
+
+// @filename: /package.json
+//// { "dependencies": { "@types/classnames": "*" } }
+
+// @filename: /tsconfig.json
+//// {}
+
+// @filename: /node_modules/@types/classnames/package.json
+//// { "name": "@types/classnames", "types": "index.d.ts" }
+
+// @filename: /node_modules/@types/classnames/index.d.ts
+//// declare const classNames: () => string;
+//// export = classNames;
+//// export as namespace classNames;
+
+// @filename: /SomeReactComponent.tsx
+//// import * as React from 'react';
+////
+//// const el1 = foo
;
+
+goTo.marker("1");
+
+verify.completions({
+ includes: [{
+ name: "classNames",
+ hasAction: true,
+ source: "/node_modules/@types/classnames/index",
+ sortText: completion.SortText.AutoImportSuggestions,
+ }],
+ preferences: {
+ includeCompletionsForModuleExports: true,
+ }
+});
diff --git a/tests/cases/fourslash/completionsImport_umdModules3_script.ts b/tests/cases/fourslash/completionsImport_umdModules3_script.ts
new file mode 100644
index 0000000000000..cdcf6da2287ea
--- /dev/null
+++ b/tests/cases/fourslash/completionsImport_umdModules3_script.ts
@@ -0,0 +1,32 @@
+///
+
+// @filename: /package.json
+//// { "dependencies": { "@types/classnames": "*" } }
+
+// @filename: /tsconfig.json
+//// { "compilerOptions": { "module": "es2015" }}
+
+// @filename: /node_modules/@types/classnames/package.json
+//// { "name": "@types/classnames", "types": "index.d.ts" }
+
+// @filename: /node_modules/@types/classnames/index.d.ts
+//// declare const classNames: () => string;
+//// export = classNames;
+//// export as namespace classNames;
+
+// @filename: /SomeReactComponent.tsx
+////
+//// const el1 = foo
+
+goTo.marker("1");
+
+verify.completions({
+ includes: [{
+ name: "classNames",
+ hasAction: undefined, // Asserts to have no actions
+ sortText: completion.SortText.GlobalsOrKeywords,
+ }],
+ preferences: {
+ includeCompletionsForModuleExports: true,
+ }
+});