Skip to content
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

Enable Go to Implementation in Typescript Editors #6209

Closed
doliver3 opened this issue Dec 22, 2015 · 133 comments · Fixed by #48264
Closed

Enable Go to Implementation in Typescript Editors #6209

doliver3 opened this issue Dec 22, 2015 · 133 comments · Fixed by #48264
Assignees
Labels
API Relates to the public API for TypeScript Domain: Symbol Navigation Relates to go-to-definition, find-all-references, highlighting/occurrences. Experience Enhancement Noncontroversial enhancements Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Suggestion An idea for TypeScript VS Code Tracked There is a VS Code equivalent to this issue

Comments

@doliver3
Copy link

Could you provide a way for Typescript Editors to list the implementations of a type?
This would definitely help developer productivity to be able to find implementations of types faster.

For example, in the Atom Editor atom-typescript plugin you can press F12 to 'Go to Declaration' which as currently implemented you often arrive at the typescript .d.ts file which has the function signature but not the actual implementation.

Since the Typescript parser often generates the d.ts files from the .ts implementation files. Could that association between the d.ts and .ts files be preserved (perhaps output with a typescript compiler option) so that Typescript editors could take developers to a list of the implementing classes or functions?

I opened a similar request for the Atom-typescript editor, but they indicate that they cannot implement this without Typescript parser support:
TypeStrong/atom-typescript#790

@DanielRosenwasser
Copy link
Member

So you want this functionality to jump to the corresponding .js if available, provided that the definition is ambient, correct?

@DanielRosenwasser DanielRosenwasser added Suggestion An idea for TypeScript API Relates to the public API for TypeScript labels Dec 22, 2015
@DanielRosenwasser
Copy link
Member

@doliver3
Copy link
Author

So you want this functionality to jump to the corresponding .js if available, provided that the definition is ambient, correct?
Yes this is a scenario that would be very useful for productivity. This alone would be very valuable. I believe the atom-typescript author believes more hooks in the Typescript compiler would make it easier for him to implement this. I'm unclear on whether this is information on js implementation line numbers is information the typescript compiler would typically know internally.

In addition, another scenario would be enabling a jump to the original typescript .ts file definition in the library being used by the application. I would imagine this information is available pre-compile to d.ts and .js files. We now have entire sets of libraries being written in .ts files as source outputting ES5 syntax js. It would be nice to achieve the ability to jump to the original typescript implementation definition in the .ts files.

I'm aware this is asking even more to jump to the .ts file implementation in the required library as it might need source map usage or distribution of source/link to original ts source. It would seem to me that the typescript compiler that generates the initial library of functions and classes would know the lines where the implementation is at and could preserve the line numbers when the library is distributed somehow so that the typscript compiler of the application using the class could know what line to jump to in the library.

Is this information on line number of implementing function/class available in source maps? Are there other sources of this information?

@DanielRosenwasser DanielRosenwasser added Visual Studio Integration with Visual Studio and removed Visual Studio Integration with Visual Studio labels Dec 23, 2015
@DanielRosenwasser
Copy link
Member

Given that we are going to be using the --allowJS flag, the language service should be able to work with the JS files.

I don't know how .d.ts files and .js files currently work together in that respect. @sheetalkamat probably (definitely) knows more about this than I do.

@mhegazy mhegazy added the Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. label Jan 4, 2016
@waderyan waderyan added the VS Code Tracked There is a VS Code equivalent to this issue label Sep 14, 2016
@mhegazy mhegazy added this to the TypeScript 2.1 milestone Sep 15, 2016
@mhegazy mhegazy removed the Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. label Sep 15, 2016
@riknoll riknoll reopened this Sep 15, 2016
@riknoll
Copy link
Member

riknoll commented Sep 15, 2016

Reopening, because going to js files isn't supported quite yet

@ubershmekel
Copy link
Contributor

ubershmekel commented Jun 23, 2017

Any updates on this one? The current state of typescript is that you cannot jump to the implementation of code in many prominent libraries.

This issue has been moved/closed/duped/deduped multiple times and fixing this bug could be a huge productivity boost.

https://github.com/ubershmekel/vscode-ts-goto-source has a project that reproduces the issue. As explained in microsoft/vscode#26325 and referenced in microsoft/vscode#10806 and microsoft/vscode#18321

Note I had to use "typescript.disableAutomaticTypeAcquisition": true from one point to use the javascript "go to definition" because it seems the .d.ts files take over if found.

@mmc41
Copy link

mmc41 commented Aug 10, 2017

@DanielRosenwasser Any updates on this? - Single most wanted feature for me.

@kevinwang930
Copy link

kevinwang930 commented Nov 1, 2021

@sabetAI I think the reasonable explanation is that go to implementation has nothing to do with typescript, Actually if you delete all the type declaration files go to implementation works.


second edit

@justingrant this problem is a purely technical issue, remove my wild guess

@justingrant
Copy link
Contributor

I'm happy to see continued enthusiasm for solving this problem. Keep the upvotes and (especially) constructive suggestions and PRs coming! Like many hard things, eventually I'm sure we'll help to get a solution built for this annoying gap in the TS developer experience.

@sabetAI I think the reasonable explanation is that go to implementation has nothing to do with typescript, and as a typescript team they definitely want everyone use typescript, so they has less willingness to improve the javascript user experience. Actually if you delete all the type declaration files go to implementation works.

As far as I can tell, this impression is not correct. Almost all* packages that are written in TS, transpiled to JS, and published to npm don't work with "Go To Implementation" any more than packages originally written in JS.

I said "almost all" above because there is a way to make it work: using the declarationMap tsconfig compiler option. But:

  1. This setting is not enabled by default. IMHO it should be enabled by default whenever sourceMap is enabled. (Maybe also when inlineSourceMap is enabled?)
  2. There is AFAICT no evangelism from the TS team (or anyone else!) about how package authors should enable this setting and include declaration map files when publishing their packages to npm.
  3. There's also no push to get declaration map files into existing DefinitelyTyped packages. Could this be automated instead of relying on 1000s of type-package maintainers to do it?

Anyone who wants to see this problem get better could:

  1. Send a PR to try to change the default of declarationMap to be true if the sourceMap or inlineSourceMap option is true. This minor change would probably have the biggest impact on this problem over time.

  2. Send a PR to update the TS docs to be more vehement that declarationMap should be enabled for all library packages, and explaining why ("because "Go To Implementation" in VS Code relies on declaration map files"). These documentation changes will be crucial if (1) is not approved.

  3. Send a PR that adds or extends the TS docs with specific guidance for package authors, including "publish your sourcemaps" and "publish declaration maps".

  4. Write a tool that will automatically add declaration map files to all compatible DefinitelyTyped packages, and convince the DefinitelyTyped maintainers to merge the output of that tool into every compatible DefinitelyTyped package. Part of the work would be figuring out what "compatible" means and what packages' declaration maps can't be automated. Note that @weswigham above was pessimistic that this automation would be possible. But I wonder if things have improved since then to make automation possible? Or if it'd be possible for a large subset of packages? Here's what he said:

There's no easy way to navigate to the JS or TS implementation of a TS type if that type is declared in a DefinitelyTyped package. (or other cases where .d.ts isn't colocated with the implementation)

Technically if you wanted to hand spin some sourcemaps to go with a DT package, it could kinda work out already. But there's definitely no automated solution here. Any solution we do have is based on improving scenarios involving TS compiler output, at those are the only times when we can otuput the additional metadata required to make the correct associations between files. Some packages support this today, I believe - I was using the azure js sdk the other day and debugging some stuff, and was pleasantly surprised when I went to some definitions and discovered they were in the original source. So yeah, it works with TS sources that have up-to-date --declarationMaps output bundled with them.

  1. Send a PR to change the build actions for DefinitelyTyped to warn users if they try to add a new package that lacks a declaration map. Not sure if this is something that can be done outside the DT maintainer team, depending on how the existing DT toolchain works. Someone who knows DT better than me could answer this.

The community has agency! If we want things to get better, any of the items above can make things better.

There's also IMHO another confusion with "Go to Definition" vs. "Go To Type Definition" are implemented. My preference would be for "Go to Type Definition" to navigate to the types and "Go to Definition" to navigate to the implementation. Not sure this is worth changing community expectations, though, given how long the current behavior has been in place. For more details, see: #6209 (comment)

@justingrant
Copy link
Contributor

Go To Type Definition doesn't work when the selection is itself a type. You'll get a "no type definition found" error.

I think y'all should open a new issue on that one. That's just a failure of exepections/bug, imo. Minimally, the error could be made better - something like "selection is only a type and so has no type definition associated with its value".

@weswigham - sorry for delayed reply, I just opened #46627 for this.

@andrewbranch
Copy link
Member

andrewbranch commented Nov 2, 2021

Thanks @justingrant! I want to make a few observations.

If I understand correctly, the thing in highest demand here is to be able to jump (whether as an explicit action or automatically under the hood as part of an existing UI action) from a location in a .d.ts file to a location in a .js file (and perhaps a .ts file is also an acceptable target for some people if it exists). The declaration maps and source maps generated by the TypeScript compiler allow you to jump from a location in an output file (.js or .d.ts) to a location in an input file (typically .ts, but could be .js).

On top of this, I’ll add some assertions that I think most people would agree with:

  • Most npm libraries written in TypeScript do not publish their .ts sources to npm; they publish only the .js and .d.ts outputs.
  • DefinitelyTyped packages often do not track versions 1:1 with their implementation libraries; DT is updated asynchronously by volunteers, and furthermore, many patch version bumps of the implementation libraries do not require updates to DT as these patches typically don't change the public API surface.

Putting all this together, I can draw a few intermediate conclusions:

  • Even if it were possible to auto-generate declaration maps for DefinitelyTyped, it would not be practical because the chances are extremely low that any user who obtains that declaration map would have the exact version of the implementation library that it was generated against. Every time the implementation library changes anything, even just adding a newline somewhere, the DT package would have to be regenerated against that source, and users would have to update them in lockstep or else they’d get sent to an inaccurate file / line number. This is a total non-starter.
  • Turning our attention away from the DefinitelyTyped problem and toward libraries written in TypeScript: enabling and shipping declaration maps alone would not change anything; those libraries would need to ship the declaration maps and the .ts source files in order for us to use the declaration maps. If libraries started doing that, we could easily jump from the .d.ts to the .ts (or skip the .d.ts altogether—maybe this is already what happens?). Even in that case, though, we would have no way of getting to the .js output. I think some people would be happy just to see the .ts source, but I can also imagine pushback at the idea of making the world download TypeScript source files from npm just to light up an editor feature. I think more people would be just as happy or happier to be able to go to the .js and leave the .ts out of their node_modules. But nothing we’ve discussed so far is remotely useful in making this happen.

Because of these problems, I’m actually a little confused at the focus of this issue on declaration maps. It seems like they would help only in edge case scenarios, and I think I can categorically reject the idea that we could use them to map from DefinitelyTyped to another source. The only solution I can think of that could solve the problem both for DefinitelyTyped and for bundled type definitions is, at the time of the Go-To-Implementation request, for us to make an effort to find, parse, and bind the corresponding JS file and make an effort to find the symbol in question. This would surely fail in the face of highly dynamic or unusual JS patterns, or where .d.ts files don't cleanly map 1:1 to .js files. It could also be expensive in the face of huge bundled and minified files. This would have to be understood as a heuristic-based best effort, and perhaps a worst-case fallback would be to take you to the top of the package’s "main" (or relevant "exports") file. But I also suspect that this process would work perfectly for a lot of libraries, and personally, I think just opening up the "main" entrypoint would save me time over scrolling through hundreds of node_modules folders when I really need to track something down in the source.

@justingrant
Copy link
Contributor

Hi @andrewbranch - thanks for jumping in on this important issue. After following it for a few years, I'll add context that may help.

  • My understanding is that Go To Implementation currently works, but only for packages that publish their .d.ts, sourcemaps, declaration maps, and original sources to npm. Unless I'm mistaken, packages that are compiled with TS (an increasing number of popular packages!) can make Go To Implementation work today.
    • Caveat: TSC may emit declaration maps that work, but popular transpilers and bundlers (rollup, esbuild, babel, etc.) may not. rollup-plugin-ts has problems, and I suspect others do too. If the TS team could help those maintainers fix their support, the ecosystem would be hugely grateful!
  • Increasingly, maintainers are packaging original sources, because original sources (or inline sourcemaps) are required for easier debugging in browser dev tools and IDEs like VSCode.
    • This is especially true for the increasing number of popular packages that are being ported to TS.
    • I've pushed PRs to fix sourcemaps and ship original source for 10+ packages. If my memory is correct, only once has a maintainer refused to ship source. The others were happy to ship source because it helped their users debug their package more easily.
    • There are ecosystem changes coming (e.g. to create-react-app, perhaps later to npm publish) that may accelerate the trend of shipping original source along with sourcemaps.
  • Transpiled JS is often hard to understand, esp. for async/await or other ES6+ features that don't transpile cleanly to ES5. For this reason, the VSCode debugger's Step Into (the debugger counterpart of Go To Implementation) always only shows transpiled JS if the original source is unavailable. Seems like Go To Implementation should behave the same way, both for consistency across different ways of "navigating" and also because many users are confused by transpiled source.
  • You're 💯 correct that DT won't work with declaration maps because of version mismatches. My fault for not thinking this through before posting.
    • I'm seeing many package maintainers bundling their .d.ts with their packages to avoid versioning mismatches, or because they're porting their source to TS. There's still a lot of reliance on DT, so this trend doesn't invalidate the need for a DT-friendly solution. But it also suggests that the non-DT (bundled declarations) case is important too and will get more important over time.

For all the reasons above, I suspect that the right solution is two-tracked:

  1. For packages built with TS, packaging declaration maps (along with sourcemaps, .d.ts, and original sources) seems like a good solution, because it can provide granular, precise navigation that I'm not sure is possible with an exports-only solution. I assume it'd provide the best perf too. Also it actually may work today! But...

    • We're lacking guidance for package maintainers about how to make declaration maps, sourcemaps, etc. work correctly. IMO, what's needed is general ""how to build a library in TS" docs. Here's a possible outline for this content.
    • As noted above, non-TSC bundlers and transpilers probably need help with emitting declaration maps properly because today those maps can be broken by code splitting, tree shaking, etc.
    • Consider defaulting declarationMap to be true if the sourceMap or inlineSourceMap option is true
    • For packages with inline sourcemaps, can we use the same code that the JS debugger extension uses to show "sources" using inline sourcemaps?
  2. For packages that aren't built with TS (or where the declaration map => sourcemap => original source chain is broken), there should be a fallback solution. For example assume the following code:

// mode_modules/some-package/src/Foo.js
import doSomething from 'do-something';
class Foo {
  static bar(x) {
    doSomething(x);
  }
}
export default Foo;

// mayapp.ts
import Foo from 'some-package';
const x = Foo.bar(42);

I assume that Go To Implementation for import('some-package').Foo.bar should behave as follows:

  • If the location of bar can be resolved, e.g. via sourcemaps or some TS JIT magic, then navigate to static bar(x) {
  • If all we know is imports, then navigate to class Foo { (I'm assuming that the same magic that the IDE uses to make Go To Definition work for regular JS files will also work as long as Foo is declared at global scope.)
  • If all we know is the file (e.g. if package.json has exports) but the exported symbol cant be resolved in that file, then navigate to the first line of Foo.js
  • If we don't even know the file then navigate to main or module.

The bullet-points above are pretty hand-wavey because I don't know enough about TS and Node's module-resolution behavior. But I assume TS and/or Node-resolution experts will know what's possible!

@andrewbranch what do you think? You likely understand this stuff better than I do, so please correct me where I'm wrong above.

Why navigating to transpiled source is bad

  • I think more people would be just as happy or happier to be able to go to the .js and leave the .ts out of their node_modules.

Are you sure about this? Have you heard this sentiment from median-skill developers? I'm skeptical, because transpiled code can be really hard to understand for non-advanced developers.

For example, here's an example of the code I saw in VSCode when I first debugged into a method of AWS Amplify, Amazon's JS front-end library that wraps AWS services:

           onSuccess: function (session) { return __awaiter(_this, void 0, void 0, function () {
                var cred, e_1, currentUser, e_2;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            logger.debug(session);
                            delete user['challengeName'];
                            delete user['challengeParam'];
                            _a.label = 1;
                        case 1:
                            _a.trys.push([1, 4, 5, 9]);
                            return [4 /*yield*/, this.Credentials.clear()];
                        case 2:
                            _a.sent();
                            return [4 /*yield*/, this.Credentials.set(session, 'session')];
                        case 3:
                            cred = _a.sent();
                            logger.debug('succeed to get cognito credentials', cred);
                            return [3 /*break*/, 9];
                        case 4:
                            e_1 = _a.sent();
                            logger.debug('cannot get cognito credentials', e_1);
                            return [3 /*break*/, 9];
                        case 5:
                            _a.trys.push([5, 7, , 8]);
                            return [4 /*yield*/, this.currentUserPoolUser()];
                        case 6:
                            currentUser = _a.sent();
                            that.user = currentUser;
                            dispatchAuthEvent('signIn', currentUser, "A user " + user.getUsername() + " has been signed in");
                            resolve(currentUser);
                            return [3 /*break*/, 8];
                        case 7:
                            e_2 = _a.sent();
                            logger.error('Failed to get the signed in user', e_2);
                            reject(e_2);
                            return [3 /*break*/, 8];
                        case 8: return [7 /*endfinally*/];
                        case 9: return [2 /*return*/];
                    }
                });
            }); },

Eek! I assume that most JS developers won't easily understand happening in the state machine above. But after aws-amplify/amplify-js#2680 was merged, debugging into the same method showed the original source, which is much easier to understand:

			onSuccess: async session => {
				logger.debug(session);
				delete user['challengeName'];
				delete user['challengeParam'];
				try {
					await this.Credentials.clear();
					const cred = await this.Credentials.set(session, 'session');
					logger.debug('succeed to get cognito credentials', cred);
				} catch (e) {
					logger.debug('cannot get cognito credentials', e);
				} finally {
					try {
						// In order to get user attributes and MFA methods
						// We need to trigger currentUserPoolUser again
						const currentUser = await this.currentUserPoolUser();
						that.user = currentUser;
						dispatchAuthEvent(
							'signIn',
							currentUser,
							`A user ${user.getUsername()} has been signed in`
						);
						resolve(currentUser);
					} catch (e) {
						logger.error('Failed to get the signed in user', e);
						reject(e);
					}
				}
			},

I agree that there are some cases where sophisticated users may want to see the transpiled JS. But those are unusual cases. The normal case (and the only case that many unsophisticated developers can handle) is to show the original source, for the same reasons that we show original source in the debugger.

But I also suspect that this process would work perfectly for a lot of libraries, and personally, I think just opening up the "main" entrypoint would save me time over scrolling through hundreds of node_modules folders when I really need to track something down in the source.

I think you are correct here. It doesn't have to be perfect to add a lot of value.

@andrewbranch
Copy link
Member

Thanks for the detailed explanation, and all good points. I don’t doubt that publishing TS sources to npm for debugging purposes is becoming more common. Likewise, as you also noted, we’re seeing a slow but steady trend of packages moving away from DefinitelyTyped to ship their own types (presumably most of these are autogenerated from TS sources, but some are hand-authored or generated from a tool other than tsc). However, I feel confident that the majority of people’s node_modules today lacks TS implementation files, so any solution that does not include an attempt to resolve symbols to JS, at least when no other option is present, I think will be highly unsatisfying and confusing.

Are you sure about this? Have you heard this sentiment from median-skill developers? I'm skeptical, because transpiled code can be really hard to understand for non-advanced developers.

Nope! This was a total guess based on past experience with JS-only VS Code users who get confused (and sometimes angry 😅) when they get dropped into something that looks TypeScripty. I think there are users who would rather get dropped into the JS, but at this point I don’t have evidence to say they make up a particular ratio of all users. But, I don’t think it really matters—if we have all the pieces in place to jump to the exact right place in a .ts file, we can be nearly 100% sure that result is correct and we can calculate it very fast, so I think we should always do that. The point I should have been making was, again, that we need to be able to make a guess at the JS when the TS doesn’t exist.

I guess my thought process was, if I need to look at implementation files in node_modules, something has already gone horribly, horribly wrong, and I’m bracing for a bad time. I hopefully don’t need to fully understand generator downleveling in order to find a line to put a breakpoint on. But I’m sure my standards here are too low for long-term thinking 😄. It seems like you’re doing a very good job of thinking about how to improve things for the long game, which I very much appreciate. I was admittedly more focused on how to get acceptable results now. Point well taken that we should be thinking about both. It’s probably worth at least doing some writing about the benefits of publishing declaration maps and sources with your packages.

The bullet-points above are pretty hand-wavey because I don't know enough about TS and Node's module-resolution behavior. But I assume TS and/or Node-resolution experts will know what's possible!

I actually don’t think we know what’s possible without some experiments. My suspicion is that exports will usually be easy, and drilling down into them further will be hit-or-miss, but I don’t know.

@justingrant
Copy link
Contributor

justingrant commented Nov 5, 2021

Cool, sounds good. A few responses inline. So glad you're looking into this!

Nope! This was a total guess based on past experience with JS-only VS Code users who get confused (and sometimes angry 😅) when they get dropped into something that looks TypeScripty.

Yep. Those users have a difficult tradeoff: hard-to-read transpiled code or also-hard-to-read (for them) TS code. But this is exactly the same problem they have in the debugger today, and debugging into node_modules is much more common than using Go To Implementation for node_modules.

For this reason, I'd recommend thinking of these problems separately.

  1. How can Go To Implementation show original source (from source/declaration maps) with a fallback to transpiled JS if the mapping doesn't work? The default should be "original source" because that's consistent with how (more common) debugger use cases behave.
  2. How to easily flip from transpiled source to original source (and flip back too) in the IDE? This would affect the most common case (the debugger) as well as less common cases like Go To Implementation. FWIW, when debugging I frequently have cases where I want to view transpiled source (e.g. when I suspect the sourcemap is out-of-date after a hot reload) so this feature would be useful beyond TS haters. The UI could be a right-click command, or even a button in the upper-right-corner toolbar like the button used to navigate from a diff view to the underlying file.

I think keeping the problems separate will make it easier to make progress on both in parallel without getting stuck in arguments about whether to show TS or JS for Go To Implementation.

Question: do declaration maps that TSC emits point to transpiled code or to original source? If the former, then they'll work just like the debugger. 👍 But if the latter, then it seems like it'd be hard to find the transpiled JS. I guess TS could load the entire sourcemap of the package and see if the file/row/col that was resolved by the declaration map also shows up in a sourcemap file, and trace it back from there? Anyway, it'd be good to know whether declaration maps point to transpiled or original source.

if we have all the pieces in place to jump to the exact right place in a .ts file, we can be nearly 100% sure that result is correct and we can calculate it very fast, so I think we should always do that. The point I should have been making was, again, that we need to be able to make a guess at the JS when the TS doesn’t exist.

👍 Yep! I come back to aligning with the (more commonly used for node_modules navigation) debugger behavior: if there's original source, show that. If not, then try to fall back to something reasonable.

if I need to look at implementation files in node_modules, something has already gone horribly, horribly wrong, and I’m bracing for a bad time.

Many years ago, I was working with the VS team back when the original "Just My Code" feature was being built. There was a big debate between the C# and (especially) the C++ team whose users had a long history of viewing, debugging, and copying libraries like MFC vs. the VB team whose users were confused by library code, esp. because libraries were written in C# and C++! What's nice is that both preferences have been improved. For library-code-haters, Just My Code continues to exist and be enhanced. For library-code-lovers, it's gotten easier to view, debug into, and modify library code.

But the fact that 15 years later this debate hasn't gone away is a signal that this is a persistent difference between developers. For some devs, viewing library code is an awful, exceptional case. But for many other users, debugging, viewing, and even editing/PR-ing library code is a normal course of business, because libraries are often buggy, poorly documented, or need to be extended in some way. You see this parallel in other walks of life too. For example, if a light switch isn't working, some folks will grab some tools while others will grab a phone and call an electrician.

So I think it's helpful to assume that for many developers (but not all!) they will read, debug into, fix, and borrow library code frequently, so we should try to make it work as well as possible.

For Just My Code fans, they won't be clicking Go To Implementation anyways (because their preference is to avoid library code!) so I think this feature is really targeted only at the anti-JMC crowd.

exports will usually be easy, and drilling down into them further will be hit-or-miss, but I don’t know.

Yep, I think the same.

It’s probably worth at least doing some writing about the benefits of publishing declaration maps and sources with your packages.

What are next steps to get more attention on this? In #16792 (comment) I wrote a possible outline for this content. I'm happy to help contribute but honestly I feel unqualified to write it because I don't understand enough about the problem space. But I'd love to pair with someone to help make this content happen. LMK how I could help.

A good place to start might be to simply create a "Writing libraries in TypeScript" section in the docs and put some minimal content there. Then that section in the docs could be a honeypot to attract tips and tricks from various TS library authors via PRs. In addition to sourcemaps/decl-maps content, there could be sections about how to configure various bundlers, how to migrate from DT to bundling types, and other topics that apply to library authors.

@danieliser
Copy link

So one thing I haven't seen mentioned, though I may have missed it in this long thread, I miss seeing the actual code comments, function & parameter descriptions. Sure types are great, but knowing the package authors intention for each function is almost more valuable.

date-fns for example doesn't tell you in their .d.ts files which date is supposed to come after the other for functions like isAfter. The answer is clear in the functions actual Docblocks. And digging into a large node_modules folder to find that one js file is tedious when you need to do it a dozen times.

What VSCode gives me:

image

What the package authors intended me to see:
image

@andrewbranch
Copy link
Member

@danieliser totally agree—however, if we get a solution to this at all, it’s likely to be a “best guess” effort to find the corresponding JS from the typings. I’m ok with providing a go-to function for that because it’s better than nothing, but I don’t think we’ll achieve high enough confidence (or satisfactory performance) in that guess in order to pull in the JSDoc. This seems like a case where the answer is just to get the package authors to copy the JSDoc comments to the typings (or copy it in a DT PR). If the typings are generated from TS source, the comments will be copied to the typings automatically. If they’re missing, it means someone’s manual process or third-party tooling is insufficient and the problem should be addressed there.

@andrewbranch andrewbranch added the Needs Investigation This issue needs a team member to investigate its status. label Jan 21, 2022
@andrewbranch andrewbranch self-assigned this Jan 21, 2022
@andrewbranch
Copy link
Member

Please note the milestone change means I plan to investigate solutions to this during the 4.7 timeframe. I don’t think we have a clear path yet, so it doesn’t necessarily mean that something will ship in 4.7.

@mhofman
Copy link

mhofman commented Jan 28, 2022

I'd like to add a use case: some of our files are authored as .js files (with JSDoc style typing) with explicit/manual .d.ts files for them to express things that cannot be expressed otherwise in JSDoc (e.g. circular type definitions, function overloads, interface, etc.)

The problem is that with such files, it's impossible to "go to definition" / "go to implementation" as VS Code and other editors stop at the .d.ts file. declarationMap isn't an option since the .d.ts file is manually authored.

@andrewbranch
Copy link
Member

andrewbranch commented Mar 15, 2022

I have a prototype up at #48264 that I’m welcoming feedback on. I’m 100% sure it doesn’t cover everything but if folks are willing to give it a try, it would be helpful to gather some test cases that don’t work yet so I can see if there’s a good way forward on them.

To try it: There’s a build from @typescript-bot on the PR (copied below) that you can npm install, then ensure your VS Code window is using that build of TypeScript by opening the command palette (in a TS or JS file) and running TypeScript: Select TypeScript Version. You should see the one newly in your node_modules listed as version 4.7.0. At that point, your Go To Definition command will be replaced with the new logic that finds more JS files and ignores .d.ts files. 🚨 This is not the final experience! We are not replacing Go To Definition like this! We don’t know for sure yet where the new logic will be exposed: it might be in a new command, or its results might be merged into Go To Definition or Go To Implementation. There are technical and UX reasons why the latter might not be desirable, but if it’s in a new command, none of you would be able to test it right now without also running a custom build of VS Code. So this build temporarily replaces the existing go-to-def implementation with the new command so you can easily test it.

One specific thing to keep an eye out for in testing: There are some cases where we are quite confident in the results we return, other cases where the best we can do is jumping to the top of a file, and then other cases where we’re confident about the file but we make a number of guesses within the file. Under the hood, I am indicating whether or not the result is a guess, but this information isn’t currently exposed in VS Code. If we go forward with presenting guesses like this, it will almost certainly go along with some kind of visual indicator noting that it’s a guess. Here’s an example on import { add } from "lodash":

image

Two of these guesses are right, while the top one is wrong. If you notice more places containing wrong guesses like this, please note that and tell me how to repro them on the PR. I need a bit of crowdsourcing to determine whether the guesses are worth doing at all and if there’s an easy way to improve them.

Thanks all!

Hey @andrewbranch, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/122072/artifacts?artifactName=tgz&fileId=F1B646030001FF6586C865D86A3B212F194CAFCD7C9C74E8E24C4BEC6A44B7E502&fileName=/typescript-4.7.0-insiders.20220316.tgz"
    }
}

and then running npm install.

@andrewbranch
Copy link
Member

The plan is to add an experimental new command in VS Code to trigger the behavior added in #48264. I’ll keep this thread updated to let you know when you can try it out in VS Code Insiders + typescript@next.

@justingrant
Copy link
Contributor

Great progress here. Thanks @andrewbranch for your perseverance in making this happen! Can't wait to try it out.

@andrewbranch
Copy link
Member

I’ll keep this thread updated to let you know when you can try it out in VS Code Insiders + typescript@next.

I forgot 🤦‍♂️

You can try this in VS Code Insiders and typescript@next! And pretty soon it will be in the stable versions. I started an issue to gather feedback: #49003. Thanks!

@selrond
Copy link

selrond commented May 9, 2022

Already in the newest release: Visual Studio Code April 2022

@shayded-exe
Copy link

@andrewbranch Thank you thank you thank you for making this happen! You just made my life so much easier

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Relates to the public API for TypeScript Domain: Symbol Navigation Relates to go-to-definition, find-all-references, highlighting/occurrences. Experience Enhancement Noncontroversial enhancements Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Suggestion An idea for TypeScript VS Code Tracked There is a VS Code equivalent to this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.