Repository: microsoft/TypeScript
File: src/services/stringCompletions.ts (TypeScript)

Code before:
            }
            return fromContextualType() || fromContextualType(ContextFlags.None);

        case SyntaxKind.ElementAccessExpression: {
            const { expression, argumentExpression } = parent as ElementAccessExpression;
            if (node === skipParentheses(argumentExpression)) {
                // Get all names of properties on the expression
                // i.e. interface A {
                //      'prop1': string
                // }
                // let a: A;
                // a['/*completion position*/']
                return stringLiteralCompletionsFromProperties(typeChecker.getTypeAtLocation(expression));
            }
            return undefined;
        }

        case SyntaxKind.CallExpression:
        case SyntaxKind.NewExpression:
        case SyntaxKind.JsxAttribute:
            if (!isRequireCallArgument(node) && !isImportCall(parent)) {
                const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(parent.kind === SyntaxKind.JsxAttribute ? parent.parent : node, position, sourceFile);
                // Get string literal completions from specialized signatures of the target
                // i.e. declare function f(a: 'A');
                // f("/*completion position*/")
                return argumentInfo && (getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker) || getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker, CheckMode.Normal)) || fromContextualType();
            }
            // falls through (is `require("")` or `require(""` or `import("")`)

        case SyntaxKind.ImportDeclaration:
        case SyntaxKind.ExportDeclaration:
        case SyntaxKind.ExternalModuleReference:
            // Get all known external module names or complete a path to a module
            // i.e. import * as ns from "/*completion position*/";
            //      var y = import("/*completion position*/");
            //      import x = require("/*completion position*/");
            //      var y = require("/*completion position*/");
            //      export * from "/*completion position*/";
            return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) };
        case SyntaxKind.CaseClause:
            const tracker = newCaseClauseTracker(typeChecker, (parent as CaseClause).parent.clauses);
            const contextualTypes = fromContextualType();
            if (!contextualTypes) {
                return;
            }
            const literals = contextualTypes.types.filter(literal => !tracker.hasValue(literal.value));
            return { kind: StringLiteralCompletionKind.Types, types: literals, isNewIdentifier: false };
        default:
            return fromContextualType() || fromContextualType(ContextFlags.None);
    }


Review comment (suggestion):
This essentially implements the same "double request" strategy as the one introduced in https://github.com/microsoft/TypeScript/pull/52875 (and later also used in https://github.com/microsoft/TypeScript/pull/53481 and https://github.com/microsoft/TypeScript/pull/53554 )

Code after:
                return stringLiteralCompletionsForObjectLiteral(typeChecker, parent.parent);
            }
            return fromContextualType() || fromContextualType(ContextFlags.None);

        case SyntaxKind.ElementAccessExpression: {
            const { expression, argumentExpression } = parent as ElementAccessExpression;
            if (node === skipParentheses(argumentExpression)) {
                // Get all names of properties on the expression
                // i.e. interface A {
                //      'prop1': string
                // }
                // let a: A;
                // a['/*completion position*/']
                return stringLiteralCompletionsFromProperties(typeChecker.getTypeAtLocation(expression));
            }
            return undefined;
        }

        case SyntaxKind.CallExpression:
        case SyntaxKind.NewExpression:
        case SyntaxKind.JsxAttribute:
            if (!isRequireCallArgument(node) && !isImportCall(parent)) {
                const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(parent.kind === SyntaxKind.JsxAttribute ? parent.parent : node, position, sourceFile);
                // Get string literal completions from specialized signatures of the target
                // i.e. declare function f(a: 'A');
                // f("/*completion position*/")
                return argumentInfo && (getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker) || getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker, CheckMode.Normal)) || fromContextualType(ContextFlags.None);
            }
            // falls through (is `require("")` or `require(""` or `import("")`)

        case SyntaxKind.ImportDeclaration:
        case SyntaxKind.ExportDeclaration:
        case SyntaxKind.ExternalModuleReference:
            // Get all known external module names or complete a path to a module
            // i.e. import * as ns from "/*completion position*/";
            //      var y = import("/*completion position*/");
            //      import x = require("/*completion position*/");
            //      var y = require("/*completion position*/");
            //      export * from "/*completion position*/";
            return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) };
        case SyntaxKind.CaseClause:
            const tracker = newCaseClauseTracker(typeChecker, (parent as CaseClause).parent.clauses);
            const contextualTypes = fromContextualType();
            if (!contextualTypes) {
                return;
            }
            const literals = contextualTypes.types.filter(literal => !tracker.hasValue(literal.value));
            return { kind: StringLiteralCompletionKind.Types, types: literals, isNewIdentifier: false };
        default:
            return fromContextualType() || fromContextualType(ContextFlags.None);
    }