Sintaxis básica de JSDoc

Tipos de datos, funciones y clases


Cuando trabajamos con Javascript, al crear variables o constantes (o incluso objetos) no es necesario incluir el tipo de dato para identificarlos. Javascript, como lenguaje, no lo requiere, y editores como VSCode los reconocerán automáticamente por el valor asignado. Esto último es lo que se conoce como inferencia de tipos, es decir, la capacidad de detectar que tipo de dato contiene, y por lo tanto, poder mostrar un autocompletado de los métodos correspondientes a ese tipo de dato.

Sin embargo, con fragmentos de código más avanzados como funciones o clases, es necesario indicar el tipo de dato a utilizar, ya que se vuelve complejo inferirlo automáticamente. Como en Javascript no podemos indicar el tipo de dato en las declaraciones, lo más común es utilizar herramientas como JSDoc o como Typescript.

Puedes instalar extensiones como JSDoc, de forma que al escribir /** y pulsar ENTER ya te preformatea y escribe parcialmente el comentario JSDoc.

Veamos algunas etiquetas básicas y como utilizarlas para documentar ciertas partes de nuestro código:

Variables u objetos simples

No es necesario documentar con comentarios multilinea. En todo caso, se pueden utilizar comentarios de una sola línea para dar contexto o información de la variable, y que aparezca en el autocompletado del editor:

/** Nick del usuario que realiza la acción */
const author = "ManzDev";

Al escribir author y pulsar un . te aparecerá una lista con todos los métodos de String (de hecho, esto ya lo hacía el editor, sin necesidad de JSDoc), pero ahora además aparecerá el comentario de contexto que hemos establecido.

En el caso de querer forzar a utilizar un tipo, se puede utilizar la etiqueta @type:

EtiquetaDescripciónAlias
@typeIndica el tipo de dato de una variable o constante.-
/**
 * Info de un usuario
 * @type {{ username: string, email: string }}
 */
const info = {
  username: "ManzDev",
  email: "[email protected]"
}

Auque puede parecer ilógico tipar variables o constantes, ya que VSCode suele inferirlo, puede ser útil en ciertas situaciones donde la inferencia no se realiza correctamente, es insuficiente o queremos dar más contexto.

Funciones

En el caso de funciones es posible que veamos más sentido a usar JSDoc. Por defecto, los parámetros de la función, la información devuelta y algunos otros detalles no se muestran si no tenemos comentarios JSDoc.

Veamos las etiquetas útiles en el caso de las funciones:

EtiquetaDescripciónAlias
@paramIndica información del parámetro de una función.-
@returnsIndica información de los datos devueltos por la función.@return
/**
 * Realiza la suma de dos números.
 * @param {number} a Primer número a sumar.
 * @param {number} b Segundo número a sumar.
 * @returns {number} Resultado de la suma de los dos parámetros indicados.
 */
function sum(a, b) {
  return a + b;
}

Como ya hemos visto, con @param podemos documentar los parámetros de nuestras funciones, mientras que con @returns podemos documentar el tipo de dato que se devuelve en la función.

Clases

Si utilizamos clases, podemos documentarlas utilizando etiquetas como @class y @constructor, y utilizar etiquetas como @public o @private para definir la visibilidad de las propiedades y métodos, así como el @param y @returns para los métodos de la clase.

EtiquetaDescripciónAlias
@classIndica la finalidad de una clase.-
@constructorIndica que el método es un constructor.-
@publicIndica que el método o propiedad es pública.-
@privateIndica que el método o propiedad es privada.-
@paramLos métodos son funciones, por lo que se usa igual.-
@returnsLos métodos son funciones, por lo que se usa igual.@return

Veamos un ejemplo en funcionamiento:

/**
 * Representa a un usuario de nuestro sistema.
 * @class
 */
class User {
  /**
   * Crea una instancia de la clase User
   * @constructor
   * @param {string} name El nick o nombre del usuario
   * @param {number} age La edad del usuario
   */
  constructor(name, age) {
    /** @private */
    this.#name = name;
    /** @private */
    this.#age = age;
  }

  /**
   * Obtiene el nombre del usuario
   * @public
   * @returns {string} El nombre del usuario
   */
  getName() {
    return this.#name;
  }

  /**
   * Cambia la edad del usuario
   * @public
   * @param {number} newAge La nueva edad del usuario
  */
  setAge(newAge) {
    this.#age = newAge;
  }

  /**
   * Comprueba si el usuario es mayor de edad
   * @private
   * @returns {boolean} True si es adulto, false si no lo es.
   */
  #isAdult() {
    return this.#age >= 18;
  }

  /**
   * Construye un saludo del usuario
   * @public
   * @returns {string} Un texto de saludo del usuario
   */
  sayHello() {
    return `Hola, soy ${this.#name} y tengo ${this.#age} años.`;
  }
}

Recuerda que la sintaxis de # es la forma que tiene Javascript de definir propiedades o métodos privados, como explicamos en Visibilidad de propiedades de clases.

Tipos de datos personalizados

En ciertos casos puede resultarnos interesante definir un tipo de dato personalizado para reutilizarlo, que no existe en Javascript, sino que es una estructura concreta definida por nosotros.

EtiquetaDescripciónAlias
@typedefIndica un tipo de dato personalizado.-
@propertyIndica una propiedad de un objeto personalizado.-

Veamos un ejemplo. Crearemos un objeto que específicamente tiene 4 propiedades: id, codename, energy y la propiedad isSleep. Observa que lo definimos con el comentario JSDoc que contiene @typedef:

/**
 * Estadísticas del usuario
 * @typedef {Object} StatUser
 * @property {number} id El identificador del usuario
 * @property {string} codename El nombre en clave del usuario
 * @property {number} energy La energía que le queda al usuario
 * @property {boolean} isSleep Indica si el usuario está dormido
 */

/**
 * Obtiene las estadísticas de un usuario
 * @param {string} username El nombre del usuario
 * @returns {StatUser} Estadísticas del usuario
 */
function getStatsUser(username) {
  // Aquí iría un código real que obtiene información
  // del usuario pasado por username (de una BDD por ej.)
  return {
    id: 84,
    codename: "badcat",
    energy: 75,
    isSleep: false
  }
}

El ejemplo está simplificado intencionadamente para que sea sencillo de entender. Observa que en el primer bloque de comentarios se define un tipo de dato StatUser, que es un objeto con dichas 4 propiedades.

Luego, un poco más adelante, definimos una función getStatsUser() que devuelve un objeto del tipo definido anteriormente.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev