I want to make a personal library with all my js functions written.
What I really need is that I need the intellisense of VS Code to show me more hints about this functions - type of the input variables, type of the return, maybe some information about the function.
For example - a hint for substring looks like this:
and a hint for my function looks like this:
Digging a bit in VS Code I was able to find, that there are .ts files with declaration of objects, interfaces and functions (for example declaration of substring() in lid.es6.d.ts, etc.)
My first thought is whether I can make a personal .ts file with declaration of all my functions and make the intellisense refer to it too.
You don't need a .d.ts for your javascript functions, you can just use a jsDoc comment. Ex:
/**
* Does stuff
* #param {Number} params
*/
function myFun(params) {
}
Between {} is the type of the parameter. You can also add a description to your function.
VsCode will pick-up JsDoc comments and use them to show you hints. Also if you type /** and then press tab above a function it will insert a property formatted jsDoc comment base on your function to give you a starting point.
JsDoc reference here
Note: Give typescript a try, you will get the nice hints you are looking for because Typescript allows you to specify the argument types, also the output of typescript is plain TS, so you will be able to use your library anywhere you could have used it before
Yes you could write your own typings. If you don't want to use TS, you can use the JSDoc standard:
/**
* Get a survey's details and possible answers by id
* #param {Number} surveyId
*/
const getById = async (surveyId) => {
...
}
VSC is smart enough to read all that and display it when implementing.
Especially when you build services which are exported and the imported this works great.
JSDoc info: http://usejsdoc.org/about-getting-started.html
Related
So I'm trying out IntelliJ and possibly moving away from Eclipse. I see I can hover over Javascript methods and actually see some info, which is great. But how do I find out more about what is being shown to me? In the pic below, what does the "?" mean? Does 'void' mean there is not a 'return' statement?
Is this JSDoc? This is old legacy code, so I know there is not any commenting above the function to give more info, so I'd like to know what's going on here. Is this just IntelliJ extrapolating the function arguments and creating its own interpretation?
I assume there's a guide or legend out there for this. But after searching around for a while I feel like I don't know the right search term to look for. Any help is appreciated.
EDIT: We don't use TypeScript at all in our current app.
Quick documentation is mostly based on comments in code. In this case the information comes from bundled definition files (In this case, a d.ts file which is a TypeScript type defintion file). For the methods defined in the project or in its dependencies, IDEA shows information from the JSDoc comments attached to functions.
Looks as if the function is defined in a d.ts file, because explicit type declarations are used, so ? indicates optional parameter, and void means that the function is not returning a value.
In vscode, developers have the ability to hover over methods and properties of variables and objects in our code, and it will show you information regarding them. Unfortunately, that is lost once we pass the code to a module inside of another file (since javascript is statically typed). Is there any way possible for me to explicitly type a parameter passed to a module? Or maybe a source-map of some sort? An example of where I have an issue:
app.js
var express = require('express')
var app = express()
var routes = './routes/route.js'
route.js
module.exports = function(app) {
// Hovering over app doesn't show the intellisense like it does in app.js
}
Update
I have continued searching for the answer but have not found one. This is the closest to getting it to work I have got, but for some reason, the editor doesn't want to apply the type. See below:
route.js
import Express from 'Express'
/**
* #param {Express} app
*/
module.exports = function(app) {
// Hovering over app doesn't show the intellisense like it does in app.js
}
...since javascript is statically typed.
JavaScript not statically typed. It is dynamically typed.
Is there any way possible for me to explicitly type a parameter passed to a module?
Yes. Use TypeScript. It provides optional static typing.
Explanation
In the following screenshot, the Intellisense does work. It is showing that app is of type any. That is the best we can do with JavaScript, because JavaScript is dynamically typed. At compile time, app can indeed be any type. Being dynamically typed means that the type is checked only at runtime.
The first problem is that VS Code has no way to determine that app is actually of the type Express. This is why your second version of route.js seems to make sense.
The problem with that, is that object types are not supported in JSDoc as interpreted by VS Code.
VS Code internally uses the JavaScript Language Service, as shown here. The thing is, the JavaScript Language Service itself is actually TypeScript (see the links to it on the same page).
This answers your question in the following ways:
First, The JSDoc annotations supported by VS Code are the same as those supported by TypeScript. And from the TypeScript documentation, this is not supported:
/**
* #param {object} param1 - Listing properties on an object type does not work
* #param {string} param1.name
*/
function fn7(param1) {}
And that's why your second attempt didn't work.
But this is supported:
/** #type {{a: string, b: number}} */
var var12;
So if you're very adventurous indeed, you could add the most-needed properties that way. I don't think that's even worth the effort.
The final alternative would be to actually use TypeScript. It doesn't need to make a huge difference to your code and will give you the type information you need.
So I created a route.ts that looks like this:
import 'node';
import { Express } from 'Express';
module.exports = function(app: Express) {
// Your code with IntelliSense goes here
}
This preserves the type information and IntelliSense and works like a charm. The trade-off is that you require one more build step (which you can handle transparently in your task runner or with tsc --watch).
Then again, you get the IntelliSense you want without being bound to ES6 (default TypeScript config uses ES5) and without being forced to use any more TypeScript than you want. All the rest of your code can be plain JavaScript if you feel like it.
To recap, your three alternatives are:
No IntelliSense.
Type annotations that explicitly list needed properties or functions.
Use TypeScript type annotations.
Edit: I should add that I also installed the TypeScript type imports for both Node and Express. I'm not sure if they are explicitly needed, but you should probably install them if you want to go this route.
Use this:
npm install #types/node
npm install #types/express
There is a really useful feature in VS Code that enables Synthetic Default Imports. It will automatically import typing information from the JSDoc or from type definition files.
I've linked a blog post that shows you both how to get setup, and a practical example of the functionality it
I think a better solution would be this:
function myFunc() {
//damn code
}
export default myFunc
As you can see, the function is not wrapped, but requires es6 ;)
So with the new language service Salsa nearing completion (Available in 1.8.0-insider with a few environment variables set) You can get intellisense support with jsDoc comments. This is thanks to TypeScripts support for it.
However my issue is continuing that into an AngularJS service, or controller for custom types. Just to note this is for JavaScript code, not TypeScript.
Let me quickly demonstrate my setup to hopefully explain.
I define my services, controller etc as CommonJS modules (To enable framework independent code reuse, and easier organisation)
//service.js
/**
* #typedef {Object} someObj
* #prop {int} value
*/
/**
* Do some action
* #param {string} val
* #returns {someObj}
*/
exports.test = function(val) {
return {};
}
When i require this anywhere in my project VSCode picks up the JSdoc comments and gives me correct intellisense, brilliant.
So traditionally i would plug that into angular like:
angular.module('myModule').service('service', () => require('./service'));
Now is where my wonderful new intellisense dreams are crushed.
Understandably when i inject that service anywhere all intellisense is lost as VSCode nor TypeScript can be expected to understand the intricacies or every frameworks DI systems.
So I'm left a little stumped.
I had the thought of creating typing's just for the angular wrappers around my services, controllers. However upon researching it i couldn't find anyway of getting the types defined in the world of JSDoc into my definition files (I'm not a TypeScript guy).
I also had the thought of using #module syntax of jsDoc to define all my CommonJs services, controllers etc. Then using that module to set the type of each function parameter where I'm injecting in my custom modules, However I'm not entirely sure that would work looking at the docs. It seems you have to specify your #module tag with the path expected in your require call which wouldn't work with relatively required modules where that path would change. Nor does the docs mention being able to use it in the #Param tag to say this variable is this module.
The other option i considered was some extension that helps VSCode's intellisense by providing the missing link. Consume the known intellisense info when defining the service and passing it onto the instances where that service is injected. However i couldn't find any such extension, nor even if it would be possible to create.
With the advances in VSCode's intellisense thanks to Salsa and typescript is this at all possible? I had got my hopes up with the JSDoc support, but i guess too soon.
Any help would be greatly appreciated, that or any workarounds where i could change my way of working slightly to get the desired result.
I have simple example:
Javascript:
function testBut(b){
alert("!");
}
HTML:
<button onclick="testBut(this)">Test</button>
Now I run my .js script through Google Closure compiler (running from commandline), and I want to keep testBut function intact.
I read in many places that I have to use --externs option and define another file with names of exported functions, in this case it would hold just:
function testBut(b){}
And additionally I need to add funny line to my js code:
window['testBut']=testBut;
So now questions:
is that really so stupid system in Closure with two bug-prone steps to be done, in order to keep desired function?
is there no "#..." annotation that would simply suit same purpose? I tried #export, but it requires --generate_exports option, and still it generates similar ugly and useless goog.a("testBut", testBut); in target code (I tried same code, and those goog.a(...) seems simply useless), and this still requires the exports file
Ideally I'm looking for simple annotation or commandline switch that would tell "don't remove/rename this function", as simple as possible, no code added, no another file.
Thanks
Don't confuse externs and exports.
Externs - provide type information and symbol names when using other code that will NOT be compiled along with your source.
Exports - Make your symbols, properties or functions available to OTHER code that will not be compiled.
So in your simple example, you need:
function testBut(b){
alert("!");
}
window["testBut"] = testBut;
However this can be simplified even further IF testBut is only for external calls:
window["testBut"] = function(b) {
alert("!");
};
Why not always use the second notation? Because internal usage (calls within the compiled code) would then have to use the full quoted syntax which blocks type checking and reduces compression.
Why not use a JSDoc Annotation for Exports?
This question comes up a lot.
For one, there isn't global consensus on how exports should be done. There are different ways to accomplish an export.
Also, exporting symbols and functions by definition blocks dead-code elimination. Take the case of a library author. The author wishes to compile his library exporting all public symbols. However, doing so means that when other users include his library in a compilation, no dead-code elimination occurs. This negates one of the primary advantages of ADVANCED_OPTIMIZATIONS.
Library authors are encouraged to provide their exports at the bottom of the file or in a separate file so that they can be excluded by other users.
It has been suggested before to provide a command line argument to control exporting based on a namespace. IE something like --export mynamespace.*. However, no author has yet tackled that issue and it is not a trivial change.
I'm working in a java/eclipse shop writing javascript, coming from a php/netbeans background. So far, I hate eclipse, but I don't want to shift away from the general tool set. (Because of issues with our build system, we're currently on the galileo release.)
The syntax coloring is just fine, and I'm learning to live with the cockpit-like interface, but eclipse's outliner doesn't properly recognize things like the module pattern at all. Nor does it do much auto-completion on my methods. Can I do anything about that?
I tried installing Aptana, but so far, I haven't noticed any real improvements in basic editing. I see the WTP, which I may or may not have installed. (How do I find out? :) Would that help?
While I'm asking, eclipse does a lousy job with indentation, which I'm constantly having to fix, since I care about such things. Anything to be done about that?
Make sure you have installed JavaScript developer tools. See Help / About Eclipse / WTP (one of the icons at the bottom of dialog) / JavaScript Developer Tools feature
Then on your web project Project / Properties / Project Facets page and make sure JavaScript Toolkit facet is selected. After that you should see JavaScript / Code Style / Formatter page as well as other advanced pages, such as, Libraries, Validation, etc.
Use JSdoc. It will give you back outline and autocomplete! Saved my life the other day...
/**
* #type MyModule
* #memberOf __MyModule
*/
var MyModule = (/** #constructor */ function () {
function innerFunc() {
// blub
}
/**
* #memberOf MyModule
*/
api.publicFunc = function() {
// gak
};
})();
#type MyModule is mandatory and should be the same as your real module name.
#memberOf MyModule and /** #constructor */ at closure function is used to display inner functions and variables inside module closure (i.e. innerFunc()). If you use the same 'type' here as in the #type definition the public functions will be listed in the same outline in Eclipse. Alternatively we can use some other name (here __MyModule and get a separate 'outline tree' for the public methods.
#memberOf module binds the API's methods to your module/type and will make them appear in the outline as well as the auto-complete context-menu (after typing MyModule.| for example).
(Original Idea from http://www.eclipse.org/forums/index.php/m/665434/)