diff --git a/src/services/completions.ts b/src/services/completions.ts index 5aa003fd59c..659b6590715 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1000,6 +1000,7 @@ namespace ts.Completions { let completionKind = CompletionKind.None; let isNewIdentifierLocation = false; let keywordFilters = KeywordCompletionFilters.None; + // This also gets mutated in nested-functions after the return let symbols: Symbol[] = []; const symbolToOriginInfoMap: SymbolOriginInfoMap = []; const symbolToSortTextMap: SymbolSortTextMap = []; @@ -1464,7 +1465,7 @@ namespace ts.Completions { } /** - * Gathers symbols that can be imported from other files, deduplicating along the way. Symbols can be “duplicates” + * Gathers symbols that can be imported from other files, de-duplicating along the way. Symbols can be "duplicates" * if re-exported from another module, e.g. `export { foo } from "./a"`. That syntax creates a fresh symbol, but * it’s just an alias to the first, and both have the same name, so we generally want to filter those aliases out, * if and only if the the first can be imported (it may be excluded due to package.json filtering in @@ -1548,7 +1549,7 @@ namespace ts.Completions { // Don't add another completion for `export =` of a symbol that's already global. // So in `declare namespace foo {} declare module "foo" { export = foo; }`, there will just be the global completion for `foo`. if (resolvedModuleSymbol !== moduleSymbol && - every(resolvedModuleSymbol.declarations, d => !!d.getSourceFile().externalModuleIndicator)) { + every(resolvedModuleSymbol.declarations, d => !!d.getSourceFile().externalModuleIndicator && !findAncestor(d, isGlobalScopeAugmentation))) { pushSymbol(resolvedModuleSymbol, moduleSymbol, /*skipFilter*/ true); } diff --git a/tests/cases/fourslash/completionsRedeclareModuleAsGlobal.ts b/tests/cases/fourslash/completionsRedeclareModuleAsGlobal.ts new file mode 100644 index 00000000000..3dd528cde17 --- /dev/null +++ b/tests/cases/fourslash/completionsRedeclareModuleAsGlobal.ts @@ -0,0 +1,35 @@ +/// + +// 32675 - if this fails there are two copies of assert in completions + +// @esModuleInterop: true, +// @target: esnext + +// @Filename: /myAssert.d.ts +////declare function assert(value:any, message?:string):void; +////export = assert; +////export as namespace assert; + +// @Filename: /ambient.d.ts +////import assert from './myAssert'; +//// +////type Assert = typeof assert; +//// +////declare global { +//// const assert: Assert; +////} + +// @Filename: /index.ts +/////// +////asser/**/; + +verify.completions({ + marker: "", + includes: [ + { + name: "assert", + sortText: completion.SortText.GlobalsOrKeywords + } + ], + preferences: { includeCompletionsForModuleExports: true, includeInsertTextCompletions: true } +});