Introducción: ¿por qué la pregunta sobre @types/* atormenta incluso a desarrolladores experimentados?
¿Alguna vez ha perdido una hora depurando un error que, al final, se reducía a la ubicación incorrecta de un paquete @types/* en package.json? Si es así, no está solo. La pregunta «How do I decide whether @types/* goes into dependencies or devDependencies?» ha acumulado miles de visitas en Stack Overflow y se ha convertido en un verdadero dolor de cabeza para la comunidad de TypeScript.
Parecería sencillo: poner los tipos en devDependencies y listo. Pero no es tan fácil. Cuando su proyecto comienza a crecer, se integran bibliotecas de terceros, monorepositorios y pipelines de CI/CD, la colocación incorrecta de los tipos puede provocar errores fatales de compilación, caídas inesperadas en producción o, peor aún, una pérdida silenciosa de la tipificación.
En este artículo, analizaremos los 5 errores más comunes al trabajar con @types/*, aprenderemos a tomar la decisión correcta basándonos en escenarios reales y crearemos una lista de verificación que le protegerá de problemas. ¿Listo? ¡Allá vamos!
Error n.º 1: «Todos los @types/* siempre van en devDependencies» — un mito que rompe compilaciones
El consejo más popular en internet dice: «Los tipos no son código en tiempo de ejecución, por lo tanto siempre deben estar en devDependencies». Y esto en el 90% de los casos es cierto. Pero hay una excepción importante que se olvida.
Cuándo devDependencies es la elección correcta
Si está escribiendo una aplicación (servidor web en Express, frontend en React, utilidad de línea de comandos), entonces todos los @types/* deben ir sin dudas a devDependencies. Su usuario final no compila TypeScript, ejecuta JavaScript ya compilado. Los tipos solo los necesita usted durante el desarrollo.
// Ejemplo para una aplicación en Express{ "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.11.0", "typescript": "^5.3.3" }}Cuándo devDependencies es un error fatal
Ahora imagine: usted desarrolla una biblioteca que exporta tipos de TypeScript para consumidores externos. Si los tipos de su biblioteca dependen de @types/express y usted lo coloca en devDependencies, el usuario que instale su biblioteca no recibirá esos tipos automáticamente. Y su IDE comenzará a mostrar subrayados rojos.
// ❌ Incorrecto para una biblioteca que exporta tipos{ "devDependencies": { "@types/express": "^4.17.21" // ¡El usuario no verá estos tipos! }}
// ✅ Correcto{ "dependencies": { "@types/express": "^4.17.21" // Los tipos estarán disponibles para los consumidores }}Regla de oro: Si su biblioteca reexporta tipos de un paquete @types/* o los utiliza en una API pública, entonces ese paquete debe estar en dependencies. Si los tipos se usan solo internamente — devDependencies.
Error n.º 2: Ignorar la diferencia entre «lo uso en el código» y «lo uso en los tipos»
Muchos desarrolladores se confunden: «Yo importo Request de express, entonces express debe estar en dependencies». Esto es cierto para el paquete express en sí, pero no para sus tipos.
Analicemos con un ejemplo concreto. Hay tres escenarios de uso del paquete @types/lodash:
- Escenario A: Usted escribe
import _ from 'lodash'y usa_.chunk(). Los tipos solo son necesarios para la compilación —devDependencies. - Escenario B: Usted crea una función
function mySort(arr: T[]): T[]y dentro usa_.orderBy. Los tipos no salen al exterior —devDependencies. - Escenario C: Usted escribe
export function proc