microsoft / TypeScript

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

Javascript function type inference breaks across a property accessor but not a function call #60600

Open AaronAllBright opened 4 days ago

AaronAllBright commented 4 days ago

Type: Bug

I am writing a typescript declaration file declarations.d.ts that describes some interfaces and a global object. The declarations will be use to assist JavaScript developers that are writing script for an embedded v8 engine that offers global objects like the one being described.

There is a global variable Global of interface type SomeGlobal, which in turn has a property someType of interface type SomeType, and finally SomeType has a callback property of type function like (other:OtherType) => void. Here is the entire file: declarations.d.ts

interface OtherType
{
    stringProperty: string;
}
interface SomeType
{
    callback: (other:OtherType) => void;
}
interface SomeGlobal
{
    someType: SomeType;
    getSomeType(): SomeType;
}

declare var Global: SomeGlobal;

// This is not part of the declarations, it's here to show you that the type of `o` is properly inferred through the property accessor `someType`
Global.someType.callback = (o) => {o.stringProperty}

and the jsconfig.json being used to ensure that code in main.js can see these types:

{
    "compilerOptions": {
        "target": "es6",
        "lib": ["es6"],
        "strict": true
    },
    "include": [
        "*.js",
        "declarations.d.ts"
    ]
}

From here on, working a in main.js that looks like this:

Global.someType.callback = (other) => {};

Global.getSomeType().callback = (other) => {};

In VSCode when you attempt to assign the callback property of SomeType and open the parentheses to start building the arrow function like so:

Global.someType.callback = (

I would expect to see autocomplete help like callback(other: OtherType): void, prompting me to complete the statement like:

Global.someType.callback = (other) => {/* do something*/};

But this is not what happens. If I hover over callback VS will display the appropriate signature for the property (property) SomeType.callback: (other: OtherType) => void, but inside the arrow function param list or function body, the other param just shows up as type any.

What's interesting is that if I go through a function call instead of a property:

Global.getSomeType().callback = (

Then there is correct function type inference for callback and I get the intellisense autocomplete you'd expect.

Am I just missing something silly here, or have I found a bug?

I have attached the 3 demo files for you to inspect. Any help would be most appreciated!

VS Code version: Code 1.95.3 (f1a4fb101478ce6ec82fe9627c43efbf9e98c813, 2024-11-13T14:50:04.152Z) OS version: Windows_NT x64 10.0.22635 Modes:

System Info |Item|Value| |---|---| |CPUs|Intel(R) Core(TM) i9-7900X CPU @ 3.30GHz (20 x 3312)| |GPU Status|2d_canvas: enabled
canvas_oop_rasterization: enabled_on
direct_rendering_display_compositor: disabled_off_ok
gpu_compositing: enabled
multiple_raster_threads: enabled_on
opengl: enabled_on
rasterization: enabled
raw_draw: disabled_off_ok
skia_graphite: disabled_off
video_decode: enabled
video_encode: enabled
vulkan: disabled_off
webgl: enabled
webgl2: enabled
webgpu: enabled
webnn: disabled_off| |Load (avg)|undefined| |Memory (System)|63.68GB (33.97GB free)| |Process Argv|. --crash-reporter-id 4c3d0139-457c-4b56-b000-09d11a0fb061| |Screen Reader|no| |VM|40%|
Extensions (57) Extension|Author (truncated)|Version ---|---|--- terraform|4op|0.2.5 vscode-base64|ada|0.1.0 github-markdown-preview|bie|0.3.0 markdown-checkbox|bie|0.4.0 markdown-emoji|bie|0.3.0 markdown-footnotes|bie|0.1.1 markdown-mermaid|bie|1.27.0 markdown-preview-github-styles|bie|2.1.0 markdown-yaml-preamble|bie|0.1.0 vscode-markdownlint|Dav|0.57.0 vscode-eslint|dba|3.0.10 gitlens|eam|16.0.4 go|gol|0.42.1 terraform|has|2.34.0 vscode-drawio|hed|1.6.6 vscode-ansi|ili|1.1.7 svg|joc|1.5.4 compare-folders|mos|0.25.1 vscode-docker|ms-|1.29.3 csdevkit|ms-|1.13.9 csharp|ms-|2.55.29 vscode-dotnet-runtime|ms-|2.2.3 vscode-kubernetes-tools|ms-|1.3.18 debugpy|ms-|2024.12.0 isort|ms-|2023.10.1 python|ms-|2024.20.0 vscode-pylance|ms-|2024.11.3 jupyter|ms-|2024.10.0 jupyter-keymap|ms-|1.1.2 jupyter-renderers|ms-|1.0.21 vscode-jupyter-cell-tags|ms-|0.1.9 vscode-jupyter-slideshow|ms-|0.1.6 remote-containers|ms-|0.388.0 remote-ssh|ms-|0.115.1 remote-ssh-edit|ms-|0.87.0 remote-wsl|ms-|0.88.5 vscode-remote-extensionpack|ms-|0.26.0 azurecli|ms-|0.6.0 cpptools|ms-|1.22.11 makefile-tools|ms-|0.11.13 remote-explorer|ms-|0.4.3 remote-server|ms-|1.5.2 fabric8-analytics|red|0.9.5 java|red|1.36.0 vscode-yaml|red|1.15.0 LiveServer|rit|5.7.9 p5-vscode|sam|1.2.16 rewrap|stk|1.16.3 code-spell-checker|str|4.0.21 intellicode-api-usage-examples|Vis|0.2.9 vscodeintellicode|Vis|1.3.2 vscode-gradle|vsc|3.16.4 vscode-java-debug|vsc|0.58.1 vscode-java-dependency|vsc|0.24.1 vscode-java-pack|vsc|0.29.0 vscode-java-test|vsc|0.43.0 vscode-maven|vsc|0.44.0
A/B Experiments ``` vsliv368cf:30146710 vspor879:30202332 vspor708:30202333 vspor363:30204092 vscod805:30301674 binariesv615:30325510 vsaa593cf:30376535 py29gd2263:31024239 c4g48928:30535728 azure-dev_surveyone:30548225 a9j8j154:30646983 962ge761:30959799 pythonnoceb:30805159 asynctok:30898717 pythonmypyd1:30879173 h48ei257:31000450 pythontbext0:30879054 cppperfnew:31000557 dsvsc020:30976470 pythonait:31006305 dsvsc021:30996838 f3je6385:31013174 dvdeprecation:31068756 dwnewjupyter:31046869 nativerepl1:31139838 pythonrstrctxt:31112756 cf971741:31144450 iacca1:31171482 notype1:31157159 5fd0e150:31155592 dwcopilot:31170013 stablechunks:31184530 ```

tssandbox.zip

AaronAllBright commented 3 days ago

Thanks for the reassignment @mjbvz. FWIW, I can confirm that this works properly in WebStorm, so it does seem to be an issue with VSCode or its built-in TypeScript or JavaScript extension.