Skip to content

IntelliSense/autocomplete doesn't work properly inside object literals #48915

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ArturAbdullin opened this issue May 2, 2022 · 11 comments · Fixed by #49735
Closed

IntelliSense/autocomplete doesn't work properly inside object literals #48915

ArturAbdullin opened this issue May 2, 2022 · 11 comments · Fixed by #49735
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@ArturAbdullin
Copy link

Does this issue occur when all extensions are disabled?: Yes

  • VS Code Version: 1.66.2 (system setup)
  • OS Version: Microsoft Windows Version 21H1 (OS Build 19043.1526)

Steps to Reproduce:

  1. Create a new object using object literal with two or more properties and a method:
    let obj = { x: 10, y: [1], fun: function () {}
  2. Now, inside the method, addressing to the properties using this keyword is recognised by the IntelliSense/autocomplete.
    this. - results in
    step2
  3. Change the value of a property inside the method, for instance
    let obj = { x: 10, y: [1], fun: function () {this.x = 5;}}
  4. Now, only addressing to the property x is recognised by the IntelliSense/autocomplete:
    step4
    Even though y property is an array, IntelliSense won't show its methods and properties:
    step4 2
System info
CPUs Intel(R) Core(TM) i5-6600 CPU @ 3.30GHz (4 x 3312)
GPU Status 2d_canvas: enabled canvas_oop_rasterization: disabled_off direct_rendering_display_compositor: disabled_off_ok gpu_compositing: enabled multiple_raster_threads: enabled_on oop_rasterization: enabled opengl: enabled_on rasterization: enabled raw_draw: disabled_off_ok skia_renderer: enabled_on video_decode: enabled video_encode: enabled vulkan: disabled_off webgl: enabled webgl2: enabled
Load (avg)
Memory (System) 15.89GB (4.73GB free)
Process Argv ...\vscode issue --crash-reporter-id 85c4d140-e4d5-49f1-8a5a-495612b0049f
Screen Reader no
VM 0%
Extensions: none

A/B experiment info
vsliv368cf:30146710
vsreu685:30147344
python383:30185418
vspor879:30202332
vspor708:30202333
vspor363:30204092
pythonvspyl392:30443607
pythontb:30283811
pythonvspyt551:30345470
pythonptprofiler:30281270
vshan820:30294714
vstes263:30335439
vscorecescf:30445987
pythondataviewer:30285071
vscod805cf:30301675
pythonvspyt200:30340761
binariesv615:30325510
bridge0708:30335490
bridge0723:30353136
vsaa593:30376534
vsc1dst:30438360
pythonvs932:30410667
wslgetstarted:30449410
pythonvsnew555:30457759
vscscmwlcmt:30465135
cppdebugcf:30475217
@mjbvz mjbvz transferred this issue from microsoft/vscode May 2, 2022
@mjbvz mjbvz removed their assignment May 2, 2022
@andrewbranch andrewbranch added the Needs Investigation This issue needs a team member to investigate its status. label May 3, 2022
@andrewbranch
Copy link
Member

@sandersn not sure if this is a known limitation—can you help triage?

@sandersn
Copy link
Member

sandersn commented May 4, 2022

I can't remember, but it's surprising and undesirable enough that I want to double-check.

Initial investigation shows that the problem is in the checker, not completions. Compare the type of this in fun vs f2:

export { }
let obj = {
  x: 10,
  y: [1],
  fun: function() {
    this.x = 1
    this/*1*/
  },
  f2: function() {
    this.x
    this/*2*/
  }
}

In fun, it's this: this; in f2 it's this: { x: number, y: number[], fun: typeof fun, f2: () => void }

I'm pretty sure that the assignment to this.x incorrectly makes the checker treat fun as its own class, instead of a method on obj.

@sandersn sandersn added Bug A bug in TypeScript and removed Needs Investigation This issue needs a team member to investigate its status. labels May 4, 2022
@sandersn sandersn added this to the TypeScript 4.8.0 milestone May 4, 2022
@jakebailey
Copy link
Member

Is it possible to write a class and export it via CommonJS in such a way that we can't actually figure out if it's supposed to be a class or object?

e.g: Playground Link

module.exports = {
    SomeClass: function() {
        this.x = 1;
    }
}

const a = new module.exports.SomeClass()
console.log(a.x)

@andrewbranch
Copy link
Member

I would think you might need /** @class */ to disambiguate, but I could be way oversimplifying things.

@andrewbranch
Copy link
Member

In fact, IIRC, it used to be the case that all classy-functions needed /** @class */ to get their own this scope. Later I think we added some heuristic about declarations to this properties that made that unnecessary. But in a context like you wrote where the this could be seen as ambiguous, the @class tag may still be useful.

@andrewbranch
Copy link
Member

What the heck, enter changed behavior overnight.

@andrewbranch andrewbranch reopened this Jun 29, 2022
@jakebailey
Copy link
Member

So just to clarify what we're looking to do, we want to tweak that heuristic such that this issue's case is treated as an object, not as a class? Looking at the playground, it appears as though v4.0 was the first version where the this in fun was this: this and not this: { object literal }, so that's helpful.

@andrewbranch
Copy link
Member

That feels reasonable to me, because

  • Who would write a class right there, as a property assignment in an object literal?
  • We already have a way to make a function act like a class, so there is an escape hatch and we don’t have to invent one just for this case.

It would technically be a breaking change, but it feels worth it if I’m making some assumptions about prevalence of these patterns. Probably should wait until 4.9 though.

@jakebailey
Copy link
Member

Thanks!

I'll bisect this just to see where the behavior changed, but I'll wait for 4.9 to change (especially if it was intentional back then; I'm sure it was).

@jakebailey
Copy link
Member

#39447 where this particular test changes, as isJSConstructor is now used consistently; on a function without a JSDoc tag, it returns true if the func contains members, which matches the behavior we're seeing here. It seems simple enough to check if this is part of an object literal (after the escape hatch before the member check).

@jakebailey
Copy link
Member

Sent #49735; there was an existing test encoding this behavior already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
6 participants