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
:
Etiqueta | Descripción | Alias |
---|---|---|
@type | Indica 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:
Etiqueta | Descripción | Alias |
---|---|---|
@param | Indica información del parámetro de una función. | - |
@returns | Indica 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.
Etiqueta | Descripción | Alias |
---|---|---|
@class | Indica la finalidad de una clase. | - |
@constructor | Indica que el método es un constructor. | - |
@public | Indica que el método o propiedad es pública. | - |
@private | Indica que el método o propiedad es privada. | - |
@param | Los métodos son funciones, por lo que se usa igual. | - |
@returns | Los 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.
Etiqueta | Descripción | Alias |
---|---|---|
@typedef | Indica un tipo de dato personalizado. | - |
@property | Indica 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.