I’ve been working around JavaScript for over four years. I write more code and read more code. I sincerely feel that it is not ability to write code that others cannot understand. It is really great to write code that everyone can understand. As we all know, JavaScript is a weakly typed scripting language, which means that it’s not obvious from the editor what the code is doing, and some things are not known until the code is actually running. In order to solve the problem of high maintenance cost of JavaScript in large projects, our team started to use TypeScript some time ago. However, the code accumulated in the past few years can not be changed all at once, so this refactoring will be a long process. We need to maintain our JavaScript projects while refactoring, and JSDoc is an intermediate solution that allows us to make JavaScript projects easier to maintain and more readable in the form of comments.

role

I use VS Code editor, built-in support for JSDoc, but also according to some constants, syntax to deduce the corresponding type can be very convenient in the editor to see the effect, so all the following examples are based on VS code to do.

First of all, JSDoc doesn’t have any impact on the source code, everything is written in comments. So there’s no need to worry about how JSDoc will negatively impact your application.

We can start by looking at how a normal JavaScript file looks in an editor:

Obviously, the editor can’t be sure what this function means, because two parameters of any type can be added. So the editor uses a common TypeScript any keyword that identifies any type to describe function parameters and return values.

In this case, we can simply use JSDoc to manually describe what this function does:

In fact, some functions need to manually specify @return {TYPE} to determine the return value TYPE of the function, but because our function’s job is to add two arguments and return them, the editor calculates the return value TYPE of the function.

There is no difference between the two pieces of code, and some might scoff that the code is clear enough that they do not need additional comments. This kind of blind confidence is usually broken when you take on someone else’s worse code, and then you think about what you did wrong and need to maintain it.

Or let’s put out a slightly more complicated example:

What looks like a clear and concise example, nothing wrong at all except that two asynchronous await can be merged into one. Indeed, if the code just sits there in the project and doesn’t change the requirements, then the code is perfectly fine. If the code is maintained by the author who wrote it, then the code is not at risk for maintenance.

But if one day this code is handed over to other partners to maintain. Then he might have a few questions:

  1. getUserInfoWhat is the structure of the return value of
  2. createOrderWhat is the structure of the return value of
  3. notifyWhat are the two variables passed in to the

We can only get a clue from the notify function to see some of the properties of the objects returned by the first two functions, but we still don’t know what the types of those properties are. To maintain such a piece of code, it takes up a lot of brain capacity to memorize, which is actually a very cost-effective thing. When the code is transferred to a third person, the third person needs to go through a complete process, reading and memorizing one function after another and line after line of code. If you take this as a deep understanding of the process, a mastery of the business, then I don’t think I can help you. Just as no teller at the supermarket today prides himself on being able to remember the prices of hundreds of items, why use your brain when a scanner can do that?

Basic usage

As mentioned above, JSDoc is something in a specific format that is written in comments. Most tags in JavaScript files are block-level, defined using /** XXX */, but can be written into code if you wish.

JSDoc provides a wide variety of tags for various scenarios. Not all of them are common (and with vscode, the editor can do many of the tags you need to specify manually), but some of the most common ones are:

  • @type identifies the variable type
  • @param Identifies the function parameter type and description
  • @return Identifies the return value type and description of a function

The full list can be found here Block Tags

Basically, using the three tags above has solved most of the problems. JSDoc has certain requirements for writing, for example, the line must have a structure like /** XXX */, or /* XXX */ will be ignored. In vscode, you can directly type /** at the top of the function and then press enter. The editor will automatically fill in a lot of content, including the parameter type, parameter description and the reserved position of the function description. Use the TAB key to quickly switch.

In fact, @type is used less often than the other two because it is used mostly to identify the type of a variable. The return value of the function is the assignment of the first basic type. This is basically done by vscode without having to manually specify it yourself. And the return value of another function, if we add @return to the function, then the variable that calls that function and gets the return value will be set to the same type as @return.

type

But since the other two tags have type-specific specifications, I’ll use @type as an illustration

First, all the basic types are supported in JSDoc, including numbers, strings, booleans, and so on.

/** @type {number} */
/** @type {string} */
/** @type {boolean} */
/** @type {RegExp} */

// Or a function
/** @type {function} */

// a function that takes arguments
/** @type {function(number, string)} */

// Parameters of the Object structure
/** @type {function({ arg1: number, arg2: string })} */

// a function that contains arguments and return values
/** @type {function(number, string): boolean} */
Copy the code

Enter the above comments in vscode and you can easily get a dynamic prompt. Of course, it is recommended to use @param and @return for functions

Extending complex types

The examples above are mostly based on descriptions of basic types, but in real development there are no such basic types that you can use. There must be a large number of variables, parameters, or return values of complex structural types.

With regard to function parameters, complex types can be described in JSDoc in two ways:

This can only be used in @param, and is not very reusable. If there are several definitions of the same structure, then we would have to make multiple copies of this comment, which is obviously not an elegant way to write. Or we could use two other tags, @typedef and @property, which are similar in format to the above tags and can be used wherever we need to specify the type:

Types defined using @typedef can be easily reused by specifying our defined types where needed. Similarly, such a custom type can be applied directly to @return.

param

This is an important tag, used to mark information about function parameters. The format looks like this (switching to TypeScript typically removes the type definition and uses the type definition in the code) :

/** * @param {number} Param description */
function test (param) {}// Or it can be combined with @type (though rarely)

/** * @param Param description */
function test (/** @type number */ param) {}Copy the code

Optional parameters

If we want to indicate that a parameter is optional, we can wrap the parameter name with a [].

/** * @param {number} [param] description */
function test (param) {}Copy the code

In fact, if your optional parameters already have default values in the parameter field, there is no need to add [] to indicate that, vscode will help you mark them.

// The default values mentioned in the documentation
/** * @param {number} [param=123] Description */
function test (param = 123) {}// in fact, using vscode can be simplified to
/** * @param Param description */
function test (param = 123) {}Copy the code

The effect is the same, and since we manually specify a value of the underlying type, we do not even need to specify the type. We can simply define the parameter description.

return

This tag is used to specify the return value of a function. It is used in the same way as @param, and basically both occur at the same time. The difference with @param is that since @return only has one, it does not need to specify a parameter name.

/** * @return {number} Description */
function test () {}Copy the code

Promise type return value processing

In this day and age, promises have become so ubiquitous that the return value of many functions may not be a result, but a Promise. So in vscode, there are two ways to use @return based on promises:

The type can be specified in cases where the function returns a Promise instance
/** * @return {Promise
      
       } */
      
function test () {
  return new Promise((res) = > {
    res(1)})}// Or omit the @return declaration when using async function definitions
async function test () {
  return 1
}

  // If the return value is another function or variable with a defined type, the effect is the same
async function test () {
  return returnVal()
}

/** @return {string} */
function returnVal () {}
Copy the code

summary

Going back to our original code snippet, modify it to look like the JSDoc version has been added:

/** * @typedef {Object} UserInfo * @property {number} uid User uid * @property {string} name nickname ** @typedef {Object} Order * @property {number} orderId orderId * @property {number} price order price */
async function main () {
  const uid = 1

  const orders = await createOrder(uid)

  const userInfo = await getUserInfo(uid)

  await notify(userInfo, orders)
}

@param {number} uid User uid * @return {Promise
      
       } */
      
async function getUserInfo (uid) {}/** * create Order * @param {number} uid User uid * @return {Promise
      
       } */
      
async function createOrder (uid) {}/** * Send notification * @param {UserInfo} UserInfo * @param {Order} orders */
async function notify (userInfo, orders) {}Copy the code

There aren’t actually a few lines of text added, and using JSDoc can reduce maintenance costs to some extent before switching to TypeScript, especially since there aren’t really that many comments to write manually with vscode. The benefit, however, is that maintainers can clearly see what a function does and what type a variable is. Code is documentation. And in the daily development, combined with the editor’s automatic completion, dynamic prompt functions, must be able to improve the development experience.

These are just a few of the common tags in JSDoc. In fact, there are many more features that are not mentioned. The document address is JSDoc

The resources

  • jsdoc | @return
  • jsdoc | @param
  • jsdoc | @typedef
  • jsdoc | @property