diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d3e2233bc44..64e45f2a905 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -204,7 +204,8 @@ namespace ts { // since we are only interested in declarations of the module itself return tryFindAmbientModule(moduleName, /*withAugmentations*/ false); }, - getApparentType + getApparentType, + getBaseConstraintOfType, }; const tupleTypes: GenericType[] = []; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e85f4c8c476..afebdfd7bcd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2552,6 +2552,7 @@ namespace ts { tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined; getApparentType(type: Type): Type; + /* @internal */ getBaseConstraintOfType(type: Type): Type; /* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol; diff --git a/src/services/completions.ts b/src/services/completions.ts index 6ac3762b4c7..3ec936d282f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -260,7 +260,7 @@ namespace ts.Completions { function addStringLiteralCompletionsFromType(type: Type, result: Push, typeChecker: TypeChecker): void { if (type && type.flags & TypeFlags.TypeParameter) { - type = typeChecker.getApparentType(type); + type = typeChecker.getBaseConstraintOfType(type); } if (!type) { return; diff --git a/tests/cases/fourslash/completionsKeyof.ts b/tests/cases/fourslash/completionsKeyof.ts new file mode 100644 index 00000000000..e3beae556c5 --- /dev/null +++ b/tests/cases/fourslash/completionsKeyof.ts @@ -0,0 +1,17 @@ +/// + +////interface A { a: number; }; +////interface B { a: number; b: number; }; +////function f(key: T) {} +////f("/*f*/"); +////function g(key: T) {} +////g("/*g*/"); + +goTo.marker("f"); +verify.completionListCount(1); +verify.completionListContains("a"); + +goTo.marker("g"); +verify.completionListCount(2); +verify.completionListContains("a"); +verify.completionListContains("b");