microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.07k stars 12.37k forks source link

Enable method signature completions for object literal that is implementing an interface #46590

Closed mjbvz closed 2 years ago

mjbvz commented 2 years ago

Bug Report

🔎 Search Terms

🕗 Version & Regression Information

4.5.0-dev.20211029

💻 Code

For the code:

interface IFoo {
    bar(x: number): void;
}

const obj: IFoo = {
    |
}

Trigger suggestions inside the object literal

🙁 Actual behavior

We get a suggestion for bar but accepting it only completes bar

🙂 Expected behavior

Accepting the completion for bar should also insert the method signature:

interface IFoo {
    bar(x: number): void;
}

const obj: IFoo = {
    bar(x: number): void {

    }
}
andrewbranch commented 2 years ago

This was a known limitation of the PR for 4.5, but probably won't be difficult to add in 4.6.

a-tarasyuk commented 2 years ago

@andrewbranch Should the completion of object literal elements be allowed with the includeCompletionsWithClassMemberSnippets option, or should a new option be added?

andrewbranch commented 2 years ago

@gabritto and I briefly discussed this when coming up with the name at the time. IIRC we didn’t really feel great about any options and mostly just lamented that we don’t have a way of presenting hierarchical preferences. One related thought is that for object literals we might want to give an option for whether to always use arrow function properties or to match the declaring interface—I personally tend to use arrow functions for object literal members even when the member is written as a method signature on the interface. If we do want to make that configurable, I think we would need a separate option. @gabritto @DanielRosenwasser @mjbvz what do you think?

mjbvz commented 2 years ago

@andrewbranch I think we can surface these settings sort of hierarchically in VS Code if we want. Right now have

javascript.suggest.includeCompletionsWithClassMemberSnippets

but we could expand this to something like:

javascript.suggest.classMemberSnippets.enabled
javascript.suggest.classMemberSnippets.methodStyle: "arrow"

We'd keep two distinct settings on the TS side, this would just be for the VS Code settings UI

mjbvz commented 2 years ago

Let's make sure we decide on on this before 4.5 goes so I can rename the VS Code setting if needed

andrewbranch commented 2 years ago

@mjbvz that only affects the presentation of the setting title in the UI, right?

image

This is better than nothing, but it still appears as a flat list and is kind of hard to navigate. But, properly organizing the data leaves room for UI improvements later. I like your suggestion for the setting name, though I’m now having stronger doubts about using the term “class” to control something for object literals as well. Maybe at that point we can do javascript.suggest.objectMemberSnippets.*.

andrewbranch commented 2 years ago

I think that change wouldn’t require any changes on the TS side right now; the new name can still map to the existing TS preference name.

gabritto commented 2 years ago

@andrewbranch I think we can surface these settings sort of hierarchically in VS Code if we want. Right now have

javascript.suggest.includeCompletionsWithClassMemberSnippets

but we could expand this to something like:

javascript.suggest.classMemberSnippets.enabled
javascript.suggest.classMemberSnippets.methodStyle: "arrow"

We'd keep two distinct settings on the TS side, this would just be for the VS Code settings UI

I agree with @andrewbranch, I think this is better than what we have now, but I think we want to have something more structured for these options in the future.

Also, a few other things on my mind:

andrewbranch commented 2 years ago

we'd want to separately enable completions for objects vs classes

Agreed. And you’re right, there are other significant differences. Parameters are contextually typed in object literals so there’s no need to write their type annotations. Also, in a class member position you can be fairly sure that a user starting to type a method name intends to type a whole method declaration. Not so in object literals, where it is possible to write a property assignment to an existing function instead:

import * as ts from "typescript";

const host: ts.LanguageServiceHost = {
  fileExis/*|*/
};

At this location we have no heuristics that would indicate whether the user intends to write a function literal / method declaration or a property assignment:

const host: ts.LanguageServiceHost = {
  fileExists: ts.sys.fileExists,
};

so we cannot replace the completion containing just the fileExists name. We would need to offer both options, and the two completion items need to be easy to disambiguate in the list. We need to be careful that users don’t find themselves automatically getting whole method declarations when they meant to only get a property name. It sounds like this feature needs a bit of careful UX design work.

starball5 commented 5 months ago

Related to the arrow function discussion on SO, see How to make VS Code autocomplete a callable property to an arrow function instead of a regular function?