Skip to content

No completions from tsserver for property values in generic type arguments #56299

Open
@kronodeus

Description

@kronodeus

🔎 Search Terms

"tsserver", "generic object completion", "generic intellisense", "generic typeahead", "generic completion", "generic object properties", "object property completion", "typescript server", "typescript lsp"

🕗 Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ for entries about typeahead support for generic type arguments.

⏯ Playground Link

https://www.typescriptlang.org/play?#code/C4TwDgpgBAKuEEEA8MoQB7AgOwCYGcoByAe2wiKgB9jgB3EogPigF5YAoUSWeAIRRpMOAlADeUMACcSYAFzEyFarQaUAvi3YwOHAPR6ogUHIoAcRIlcCgMIkAtmAA2EYAEsyhaSQBur3BFwueCgAUXQAQwdnBDZeSGQiZl0DKEAZcig+cKsoWyiXd2xCADkAeVQvX39A7mgwyKcIPli4SAEJL3liDSYgA

💻 Code

type TypeA<T extends 'one' | 'two'> = T
type TypeB<T extends { prop: 'one' | 'two' }> = T

// ✅ Good: Completions provided
type ExampleA = TypeA<''>

// ❌ Bad: Completions NOT provided
type ExampleB = TypeB<{ prop: '' }>

🙁 Actual behavior

Getting completions between the quotes on line 5 (using Control + Space on Mac OS) correctly provides 'one' and 'two' as options.

Screenshot 2023-11-02 at 5 38 51 PM

However, doing the same between the quotes on line 8 provides no completions.

Screenshot 2023-11-02 at 5 39 05 PM

🙂 Expected behavior

Getting completions between the quotes on both lines 5 and 8 (using Control + Space on Mac OS) correctly provides 'one' and 'two' as options.

Additional information about the issue

The type of prop is correct ('one' | 'two') and if you enter an invalid value you get the correct type error. Therefore, TypeScript should have sufficient information to provide the exact same completions in both examples.

Screenshot 2023-11-02 at 5 44 00 PM

I enabled verbose tsserver logging in Visual Studio Code and captured the requests and responses for these completion requests.

Line 5 Request:

{
    "seq":12,
    "type":"request",
    "command":"completionInfo",
    "arguments":{
        "file":"/Users/ryan.palmer/Desktop/Test.ts",
        "line":5,
        "offset":24,
        "includeExternalModuleExports":true,
        "includeInsertTextCompletions":true,
        "triggerKind":1
    }
}

Line 5 Response:

{
    "seq":0,
    "type":"response",
    "command":"completionInfo",
    "request_seq":12,
    "success":true,
    "body":{
        "isGlobalCompletion":false,
        "isMemberCompletion":false,
        "isNewIdentifierLocation":false,
        "optionalReplacementSpan":{
            "start":{
                "line":5,
                "offset":24
            },
            "end":{
                "line":5,
                "offset":24
            }
        },
        "entries":[
            {
                "name":"one",
                "kind":"string",
                "kindModifiers":"",
                "sortText":"11",
                "replacementSpan":{
                    "start":{
                        "line":5,
                        "offset":24
                    },
                    "end":{
                        "line":5,
                        "offset":24
                    }
                }
            },
            {
                "name":"two",
                "kind":"string",
                "kindModifiers":"",
                "sortText":"11",
                "replacementSpan":{
                    "start":{
                        "line":5,
                        "offset":24
                    },
                    "end":{
                        "line":5,
                        "offset":24
                    }
                }
            }
        ]
    }
}

Line 8 Request:

{
    "seq":9,
    "type":"request",
    "command":"completionInfo",
    "arguments":{
        "file":"/Users/ryan.palmer/Desktop/Test.ts",
        "line":8,
        "offset":32,
        "includeExternalModuleExports":true,
        "includeInsertTextCompletions":true,
        "triggerKind":1
    }
}

Line 8 Response:

{
    "seq":0,
    "type":"response",
    "command":"completionInfo",
    "request_seq":9,
    "success":false,
    "message":"No content available."
}

Line 8 Logs:

Info 451  [17:32:09.801] getCompletionData: Get current token: 0.018829017877578735
Info 452  [17:32:09.801] getCompletionData: Is inside comment: 0.007900983095169067
Info 453  [17:32:09.801] getCompletionData: Get previous token: 0.10709202289581299
Info 454  [17:32:09.802] getCompletionsAtPosition: isCompletionListBlocker: 0.03820300102233887
Info 455  [17:32:09.802] Returning an empty list because completion was requested in an invalid position.

As you can see, the requests are both identical except for position. But the response for the request on line 8 is empty, and there is a message indicating the position is invalid.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions