Documentación de código
La documentación de código consiste en anotar directamente el código fuente para describir el propósito, los parámetros, los valores de retorno y el comportamiento de funciones, clases y módulos. En el ecosistema JavaScript/TypeScript la herramienta estándar para esto es JSDoc, y su equivalente orientado a TypeScript es TypeDoc.
JSDoc
JSDoc es un sistema de anotaciones basado en comentarios /** ... */ que se colocan justo antes de una declaración. A partir de esas anotaciones se puede generar documentación HTML estática o proporcionar autocompletado en editores como VS Code.
Instalación:
npm install --save-dev jsdoc
Configuración básica (.jsdoc.json):
{
"source": {
"include": ["src"],
"includePattern": ".+\\.js$"
},
"opts": {
"destination": "docs/jsdoc",
"recurse": true
},
"plugins": ["plugins/markdown"]
}
Añade un script en package.json:
"scripts": {
"docs": "jsdoc -c .jsdoc.json"
}
Etiquetas JSDoc más habituales
| Etiqueta | Descripción |
|---|---|
@param | Describe un parámetro de entrada |
@returns | Describe el valor de retorno |
@throws | Documenta los errores que puede lanzar |
@typedef | Define un tipo reutilizable |
@type | Anota el tipo de una variable |
@async | Indica que la función es asíncrona |
@deprecated | Marca algo como obsoleto |
@example | Proporciona un ejemplo de uso |
@module | Indica que el fichero es un módulo |
@class | Documenta una clase |
Ejemplos prácticos
Función simple:
/**
* Calcula el precio total aplicando un descuento porcentual.
*
* @param {number} price - Precio base en euros.
* @param {number} discount - Porcentaje de descuento (0-100).
* @returns {number} Precio final tras aplicar el descuento.
* @throws {RangeError} Si el descuento está fuera del rango [0, 100].
*
* @example
* const total = applyDiscount(100, 20); // 80
*/
function applyDiscount(price, discount) {
if (discount < 0 || discount > 100) {
throw new RangeError('El descuento debe estar entre 0 y 100');
}
return price * (1 - discount / 100);
}
Función asíncrona con tipos definidos:
/**
* @typedef {Object} User
* @property {string} id - Identificador único del usuario.
* @property {string} name - Nombre completo.
* @property {string} email - Dirección de correo electrónico.
* @property {Date} createdAt - Fecha de creación de la cuenta.
*/
/**
* Obtiene un usuario de la base de datos por su ID.
*
* @async
* @param {string} userId - ID del usuario a buscar.
* @returns {Promise<User>} El objeto de usuario encontrado.
* @throws {Error} Si el usuario no existe en la base de datos.
*/
async function getUserById(userId) {
const user = await db.users.findOne({ id: userId });
if (!user) throw new Error(`Usuario ${userId} no encontrado`);
return user;
}
Clase completa:
/**
* Servicio para gestionar la autenticación de usuarios.
* Utiliza JWT para la emisión y verificación de tokens.
*
* @class AuthService
*/
class AuthService {
/**
* Crea una instancia de AuthService.
*
* @param {string} jwtSecret - Clave secreta para firmar los tokens JWT.
* @param {number} [expiresIn=3600] - Tiempo de expiración del token en segundos.
*/
constructor(jwtSecret, expiresIn = 3600) {
this.jwtSecret = jwtSecret;
this.expiresIn = expiresIn;
}
/**
* Genera un token JWT para el usuario indicado.
*
* @param {string} userId - ID del usuario autenticado.
* @returns {string} Token JWT firmado.
*/
generateToken(userId) {
return jwt.sign({ sub: userId }, this.jwtSecret, {
expiresIn: this.expiresIn,
});
}
/**
* Verifica y decodifica un token JWT.
*
* @param {string} token - Token JWT a verificar.
* @returns {{ sub: string, iat: number, exp: number }} Payload decodificado.
* @throws {JsonWebTokenError} Si el token es inválido o ha expirado.
*/
verifyToken(token) {
return jwt.verify(token, this.jwtSecret);
}
}
Buenas prácticas
- No documentes lo obvio.
// Incrementa el contador en 1debajo decounter++no aporta valor. - Documenta los contratos, no la implementación. Lo importante es qué recibe la función, qué devuelve y qué errores lanza.
- Mantén los ejemplos ejecutables. Un ejemplo que compila/funciona vale más que un párrafo de explicación.
- Usa
@deprecateden lugar de borrar. Cuando una función queda obsoleta, márcala con@deprecatedy señala la alternativa antes de eliminarla. - Revisa la documentación en los pull requests. Incluye la actualización de JSDoc/TypeDoc como parte del criterio de Definition of Done.