diff --git a/src/services/completions.ts b/src/services/completions.ts index 5a08dbcb9c8..df78ab931d1 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -173,6 +173,18 @@ namespace ts.Completions { // var y = require("/*completion position*/"); return getStringLiteralCompletionEntriesFromModuleNames(node, compilerOptions, host, typeChecker); } + else if (isEqualityExpression(node.parent)) { + // Get completions from the type of the other operand + // i.e. switch (a) { + // case '/*completion position*/' + // } + return getStringLiteralCompletionEntriesFromType(typeChecker.getTypeAtLocation(node.parent.left === node ? node.parent.right : node.parent.left), typeChecker); + } + else if (isCaseOrDefaultClause(node.parent)) { + // Get completions from the type of the switch expression + // i.e. x === '/*completion position' + return getStringLiteralCompletionEntriesFromType(typeChecker.getTypeAtLocation((node.parent.parent.parent).expression), typeChecker); + } else { const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile); if (argumentInfo) { @@ -184,7 +196,7 @@ namespace ts.Completions { // Get completion for string literal from string literal type // i.e. var x: "hi" | "hello" = "/*completion position*/" - return getStringLiteralCompletionEntriesFromContextualType(node, typeChecker); + return getStringLiteralCompletionEntriesFromType(typeChecker.getContextualType(node), typeChecker); } } @@ -228,8 +240,7 @@ namespace ts.Completions { return undefined; } - function getStringLiteralCompletionEntriesFromContextualType(node: StringLiteral, typeChecker: TypeChecker): CompletionInfo | undefined { - const type = typeChecker.getContextualType(node); + function getStringLiteralCompletionEntriesFromType(type: Type, typeChecker: TypeChecker): CompletionInfo | undefined { if (type) { const entries: CompletionEntry[] = []; addStringLiteralCompletionsFromType(type, entries, typeChecker); @@ -1756,4 +1767,15 @@ namespace ts.Completions { catch (e) {} return undefined; } + + function isEqualityExpression(node: Node): node is BinaryExpression { + return isBinaryExpression(node) && isEqualityOperatorKind(node.operatorToken.kind); + } + + function isEqualityOperatorKind(kind: SyntaxKind) { + return kind == SyntaxKind.EqualsEqualsToken || + kind === SyntaxKind.ExclamationEqualsToken || + kind === SyntaxKind.EqualsEqualsEqualsToken || + kind === SyntaxKind.ExclamationEqualsEqualsToken; + } } diff --git a/tests/cases/fourslash/completionForStringLiteral10.ts b/tests/cases/fourslash/completionForStringLiteral10.ts new file mode 100644 index 00000000000..76a98eb732f --- /dev/null +++ b/tests/cases/fourslash/completionForStringLiteral10.ts @@ -0,0 +1,12 @@ +/// + +////type As = 'arf' | 'abacus' | 'abaddon'; +////let a: As; +////if ('/**/' != a + +goTo.marker(); +verify.completionListContains("arf"); +verify.completionListContains("abacus"); +verify.completionListContains("abaddon"); +verify.completionListCount(3); + diff --git a/tests/cases/fourslash/completionForStringLiteral11.ts b/tests/cases/fourslash/completionForStringLiteral11.ts new file mode 100644 index 00000000000..f6acac28a65 --- /dev/null +++ b/tests/cases/fourslash/completionForStringLiteral11.ts @@ -0,0 +1,14 @@ +/// + +////type As = 'arf' | 'abacus' | 'abaddon'; +////let a: As; +////switch (a) { +//// case '/**/ +////} + +goTo.marker(); +verify.completionListContains("arf"); +verify.completionListContains("abacus"); +verify.completionListContains("abaddon"); +verify.completionListCount(3); + diff --git a/tests/cases/fourslash/completionForStringLiteral8.ts b/tests/cases/fourslash/completionForStringLiteral8.ts new file mode 100644 index 00000000000..727bdf6e6a4 --- /dev/null +++ b/tests/cases/fourslash/completionForStringLiteral8.ts @@ -0,0 +1,12 @@ +/// + +////type As = 'arf' | 'abacus' | 'abaddon'; +////let a: As; +////if (a === '/**/ + +goTo.marker(); +verify.completionListContains("arf"); +verify.completionListContains("abacus"); +verify.completionListContains("abaddon"); +verify.completionListCount(3); +