microsoft / TypeScript-Sublime-Plugin

IO wrapper around TypeScript language services, allowing for easy consumption by editor plugins
Apache License 2.0
1.72k stars 237 forks source link

Feature request: Could the plugin recommend "import"s for inferred types? #737

Open mcclure opened 4 years ago

mcclure commented 4 years ago

Try opening this minimal demo project https://github.com/mcclure/ts-hello-bug/tree/editor-demo in Sublime Text, and opening the file 'src/index.tsx'. index.tsx imports a function demoFunction() from 'dependencyOne.ts' and calls it. If I move the cursor over the let x in 'index.tsx', it says:

let x : DemoClass, Line 3, Column 5

Here is a problem: what is DemoClass? I didn't import any such class. If I try to say let x : DemoClass = demoFunction(), I will get error TS2304: Cannot find name 'DemoClass'., because I didn't import it. (Since I wrote the demo project myself, I know the answer: 'dependencyOne.ts' imported it from 'dependencyTwo.ts'. But let's say I don't know that.)

If I cmd-P and look at the features of the TypeScript plugin, I see it exposes a useful function: "GoTo Type Definition". If I select this option, it takes me to class DemoClass in 'dependencyTwo.ts'. Awesome, problem solved! I need to import { DemoClass } from "./dependencyTwo"`.

But consider a slightly more complicated example: What if DemoClass had been imported from a library? In this case the existing tools are less helpful. Try out this other demo project https://github.com/mcclure/ts-hello/tree/stable which is also minimal, but this one has Preact in package.json. Try npm installing, then opening 'src/index.tsx' and adding the line:

let test = <div>Test</div>

If I mouse over test it says "let test : h.JSX.Element". This is a little odder. If I "GoTo Type Definition" this, I get:

interface Element extends preact.VNode<any> {}

inside namespace JSXInternal, in jsx.d.ts. That's not actionable the way finding 'dependencyTwo.ts' was. What I want to do here, probably, is import { JSX } from "preact"; and then use the type JSX.Element. But I wouldn't figure this out by using the Sublime plugin.

I'm not sure these are the best examples. But this is a situation I did find myself in twice this weekend: There is a symbol or value I have access to by writing code. The Sublime plugin can successfully infer its type. I want to assign the value to a variable, and I want to write a type signature for that variable. But the type is not in scope, I have no idea what to import to get it in scope, and the plugin can't help me because the type is something deep inside a spaghetti of import exports in 'node_modules'.

Expected behavior/suggestion: In both the cases above, I think the plugin could have figured out the correct import line and suggested it to me. In the first case, it could have followed the import from './dependencyTwo' and detected I can import './dependencyTwo' also. In the second case, it could have noticed the JSXInternal namespace that h import exports is also import exported by the "preact" node_module (which I am already importing other symbols from) and suggested that.

(The second example might be a harder case because it would require the plugin to speculate about different ways JSXInternal could get into scope; but possibly if there are several sensible "import" routes, the plugin could show a list. Also I think the plugin has this speculation logic already, because if I type let test : JSX.Element without importing JSX, then use the mysterious "TypeScript: Request Code Fixes" feature of the plugin, it magically adds , JSX to my "import JSX" line up top (!))

I am using v3.7.3 to test.

adevart commented 4 years ago

I'm looking for the same thing. It's definitely possible to have automatic imports. The Webstorm IDE does this. It indexes projects and adds imports as you type or uses alt-enter to insert them manually.

It can be more difficult with compiled libraries because this can impact performance if it has to find references inside large compiled files.

As well as imports, it would be useful to add Typescript reference links automatically too.

https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html

Since compiled libraries tend not to change, those can be indexed manually and project files can be indexed when files are modified with an option to rebuild the project.

With an index built, whenever a class is referenced and there's no equivalent import statement, it can automatically add it. If there's more than one, it can let the editor flag the keyword and then have a menu item to "add import reference" and popup a list of choices of which to use.

There's an ImportHelper plugin for Sublime that's supposed to do this sort of thing but it gives errors for me:

https://github.com/unlight/sublime-import-helper