Back

TypeScript en Node: La Configuración Práctica

TypeScript en Node: La Configuración Práctica

Ya escribes TypeScript para el navegador. Ahora lo necesitas ejecutando del lado del servidor—para una API, un script de build o SSR. El problema: la mayoría de las guías de configuración están desactualizadas, recomendando configuraciones CommonJS o herramientas que no se alinean con Node.js moderno.

Esta guía cubre dos enfoques para tu configuración de TypeScript en Node.js: compilar con tsc y ejecutar JavaScript, o ejecutar archivos .ts directamente con la eliminación nativa de tipos de Node. Ambos funcionan. Cada uno se ajusta a diferentes escenarios.

Puntos Clave

  • Establece "type": "module" en package.json para habilitar ESM por defecto en proyectos modernos de TypeScript en Node.js
  • Usa compilación con tsc para despliegues en producción, paquetes publicados y código que utiliza enums, namespaces o parameter properties
  • Usa la eliminación nativa de tipos de Node para scripts locales, servidores de desarrollo y prototipos rápidos
  • Siempre usa import type para importaciones de solo tipos para evitar errores en tiempo de ejecución con la eliminación de tipos
  • Ejecuta tsc --noEmit en CI ya que la eliminación de tipos de Node no realiza verificación de tipos

La Base: Node 24 LTS y ESM

Comienza con esta base:

{
  "type": "module"
}

Esto habilita ESM por defecto. Tus importaciones usan sintaxis ESM, y Node resuelve los módulos en consecuencia.

Node 24 es la línea base LTS actual para esta configuración (se puede descargar desde aquí: https://nodejs.org/en/download).

Enfoque 1: Compilar con tsc, Ejecutar JavaScript

Este enfoque separa la compilación de la ejecución. Úsalo para despliegues en producción, paquetes publicados o cuando necesites soporte completo de características de TypeScript.

tsconfig para Node 24

{
  "compilerOptions": {
    "target": "ES2024",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "skipLibCheck": true,
    "declaration": true,
    "sourceMap": true,
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "lib": ["ES2024"]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Configuraciones clave en esta configuración:

  • module: NodeNext y moduleResolution: NodeNext: Coincide con el comportamiento real de resolución de módulos de Node
  • verbatimModuleSyntax: Requiere import type explícito para importaciones de solo tipos—crítico para evitar errores en tiempo de ejecución (ver documentación de TypeScript: https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax)
  • isolatedModules: Asegura compatibilidad con herramientas de transpilación de archivos individuales

Scripts

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc --watch"
  }
}

Ejecuta npm run build, luego npm start. El JavaScript compilado reside en dist/.

Enfoque 2: TypeScript Nativo de Node (Eliminación de Tipos)

Node introdujo soporte nativo de TypeScript en Node 22 y lo estabilizó en Node 24 LTS mediante la eliminación de tipos. Úsalo para scripts, herramientas locales o desarrollo cuando quieras cero pasos de build.

Documentación oficial: https://nodejs.org/api/typescript.html

Cómo Funciona

En Node 24+, ejecuta directamente:

node src/index.ts

(Las versiones antiguas de Node requerían flags experimentales; Node 24 no los necesita.)

Limitaciones Críticas

El TypeScript nativo de Node solo elimina tipos—no verifica tipos. Aún necesitas tsc --noEmit en CI o tu editor para detectar errores.

Otras restricciones:

  • Ignora tsconfig.json: Node no lee tus opciones del compilador
  • Requiere extensiones de archivo explícitas: Escribe import { foo } from './utils.js' incluso cuando el archivo fuente es utils.ts
  • Respeta las reglas de ESM vs CJS: El campo type de tu package.json importa
  • No ejecutará TypeScript desde node_modules: Las dependencias deben ser JavaScript compilado
  • Solo soporta sintaxis borrable: Enums, namespaces y parameter properties fallan a menos que habilites --experimental-transform-types

Las Extensiones de Archivo Importan

Para formatos de módulos mixtos:

  • Archivos .mts → siempre ESM
  • Archivos .cts → siempre CommonJS
  • Archivos .ts → siguen el campo type de package.json

Evitando Errores en Tiempo de Ejecución

Usa import type para importaciones de solo tipos:

// Correcto
import type { Request, Response } from 'express'
import express from 'express'

// Incorrecto - fallará en tiempo de ejecución con eliminación de tipos
import { Request, Response } from 'express'

Habilita verbatimModuleSyntax en tu tsconfig para detectar estos durante el desarrollo, aunque Node ignore la configuración en tiempo de ejecución.

Qué Enfoque Usar

Usa compilación con tsc para:

  • Despliegues en producción
  • Paquetes npm publicados
  • Código que usa enums, namespaces o parameter properties
  • Proyectos que requieren source maps en producción

Usa eliminación nativa de tipos para:

  • Scripts locales y herramientas
  • Servidores de desarrollo (combina con --watch)
  • Prototipos rápidos
  • Builds de desarrollo SSR

Una Configuración Práctica de Desarrollo

Combina ambos enfoques:

{
  "scripts": {
    "dev": "node --watch src/index.ts",
    "typecheck": "tsc --noEmit",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

El desarrollo usa ejecución nativa para velocidad. CI ejecuta typecheck. Producción despliega JavaScript compilado.

Conclusión

La configuración moderna de TypeScript en Node.js es más simple de lo que sugieren las guías antiguas. Usa ESM, configura la resolución de módulos NodeNext, y elige tu estrategia de ejecución según el contexto. La eliminación nativa de tipos funciona para desarrollo y scripts. La salida compilada funciona para producción y paquetes. Ambos enfoques comparten el mismo código fuente y tsconfig—no estás atado a ninguno de los dos.

Preguntas Frecuentes

La resolución de módulos de Node requiere extensiones de archivo explícitas para ESM. Cuando escribes import from ./utils.js, Node busca esa ruta exacta en tiempo de ejecución, incluso si tu archivo fuente es utils.ts. Dado que la eliminación de tipos remueve tipos pero no renombra archivos, y tsc genera archivos .js, usar extensiones .js en tu código fuente asegura que las importaciones funcionen en ambos escenarios.

No por defecto. Los enums requieren transformación de código, no solo eliminación de tipos. Puedes habilitar el flag --experimental-transform-types para soportar enums, namespaces y parameter properties, pero esto añade complejidad. Para configuraciones más simples, considera usar objetos const con aserciones as const como alternativa a los enums.

Para la mayoría de los casos de uso, no. La eliminación nativa de tipos de Node 24 maneja la ejecución directa de .ts. Herramientas como ts-node y tsx son conveniencias opcionales que añaden soporte para tsconfig.json, resolución de alias de rutas y transformaciones completas de TypeScript sin flags. Úsalas solo si tu configuración necesita esas características.

Cuando usas eliminación nativa de tipos, Node ejecuta tus archivos .ts directamente, por lo que los números de línea en los stack traces coinciden con tu código fuente. Para código compilado, habilita sourceMap en tsconfig.json y Node usará automáticamente los archivos .js.map para mostrar las ubicaciones originales de TypeScript en errores y sesiones del depurador.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay