Astro check falla con TypeScript 7: arreglar la dependencia sin eliminar la comprobación de tipos
Un pull request de Dependabot actualizó TypeScript de 6.0.3 a 7.0.2. Sobre el papel parece una actualización mayor como tantas otras. En un proyecto Astro, sin embargo, basta para que astro check deje de funcionar.
Al revisar una incidencia pública de un proyecto Astro/Starlight, encontré dos soluciones bastante distintas. Una consistía en quitar astro check de la CI para dejar de ejecutar la comprobación que fallaba. La otra devolvía TypeScript a la versión 6, mantenía el checker y evitaba temporalmente que Dependabot volviera a proponer la serie 7.x. La segunda fue la que acabó fusionándose.
No se trata solo de un rango de peer dependencies desactualizado. TypeScript 7.0 pasó a usar un compilador nativo y parte de las herramientas de los frameworks siguen dependiendo de la API programática de TypeScript 6. En el anuncio oficial de TypeScript 7.0, Microsoft recomendó expresamente que las integraciones con lenguajes incrustados, como Astro, Vue, Svelte y MDX, permanecieran en TypeScript 6 mientras completaban la migración.
Conviene aclarar qué comprobé realmente. Leí los archivos de dependencias fijados a un commit, los dos PR y las ejecuciones de GitHub Actions del proyecto original. También ejecuté cinco pruebas sintéticas con la biblioteca estándar de Node.js para entender cómo exports puede hacer que un paquete instalado parezca ausente. No ejecuté npm install ni astro check en ese proyecto Astro. El éxito de CI que menciono más abajo pertenece al proyecto original; no es una reproducción independiente realizada por mí.
Dos formas de salir del problema: quitar la comprobación o recuperar la versión compatible
La incidencia está documentada en vishwakarma Issue #8. Antes, Dependabot PR #3 había elevado TypeScript a 7.0.2. El mantenedor informó de problemas de compatibilidad con astro check tras ese cambio.
PR #9 propuso eliminar el propio checker: quitar el script check y la dependencia @astrojs/check de apps/web/package.json y retirar typecheck-web del Makefile. De ese modo check-web pasaba a ejecutar solo el formateo y la compilación. Ese PR se cerró sin fusionarse.
Es posible conseguir una CI verde dejando de ejecutar la prueba que aparece en rojo. Pero astro build no sustituye el diagnóstico de tipos que astro check aporta para los archivos .astro y el código TypeScript. Suprimir ese paso significa perder una garantía que el proyecto ya tenía, no recuperar su funcionamiento.
El PR #10, que sí se fusionó, mantuvo el checker y restauró la dependencia de TypeScript en el workspace web:
- "typescript": "^7.0.2"
+ "typescript": "^6.0.3"
En el commit público posterior al arreglo, apps/web/package.json declara Astro ^7.2.10 y @astrojs/check ^0.9.10. El package-lock.json de ese mismo commit fija @astrojs/[email protected] con este requisito:
"peerDependencies": {
"typescript": "^5.0.0 || ^6.0.0"
}
Se trata de una declaración inspeccionada en el lockfile, no de un mensaje de npm producido durante una ejecución mía. Para esa versión concreta del checker, TypeScript 7 queda fuera del rango de compatibilidad declarado.
También hay evidencia de ejecución después del arreglo. GitHub Actions #38103905437 corrió con el head del PR 5d828e8d55c5db833f5cca17f28da3b6aba05a99. En el trabajo web pasaron make setup-web y make check-web, y el trabajo Python terminó correctamente. Esto respalda el estado corregido que conserva la comprobación, pero no significa que haya reproducido por mi cuenta el fallo con TypeScript 7.
¿Cómo puede parecer que falta TypeScript si está instalado?
Hay dos niveles distintos de incompatibilidad.
El más profundo tiene que ver con la API del compilador. TypeScript 7.0 migró a una implementación nativa en Go. Que el ejecutable tsc funcione no implica que siga presente la API programática estable que ofrecía TypeScript 6. Astro necesita integrar el análisis de TypeScript dentro de los archivos .astro mediante sus herramientas de lenguaje. Actualizar el compilador de línea de comandos no resuelve esa integración por sí solo.
El segundo nivel confunde especialmente el diagnóstico. En el Issue #17268 de Astro se documentó cómo los cambios en exports del paquete TypeScript 7 podían hacer que una comprobación antigua basada en require.resolve('typescript') lanzara ERR_PACKAGE_PATH_NOT_EXPORTED. Si una herramienta convierte cualquier excepción de resolución en «TypeScript no está instalado», el usuario recibirá una pista equivocada.
Quise comprobar de manera independiente ese mecanismo más pequeño sin instalar todo Astro ni el TypeScript 7 real. Con la biblioteca estándar de Node.js v22.16.0 generé dos paquetes simulados y desechables: uno con un punto de entrada clásico y otro que solo exportaba ./package.json, sin exportar la raíz del paquete. Esta es la parte relevante de la configuración generada para la prueba, con el formato ligeramente simplificado:
{
name: 'native-ts-synthetic',
version: '7.0.0-fixture',
type: 'module',
exports: {
'./package.json': './package.json'
}
}
En ese paquete sintético, require.resolve('native-ts-synthetic') devuelve ERR_PACKAGE_PATH_NOT_EXPORTED aunque los archivos existan. Como la simulación sí exporta explícitamente ./package.json, ese subpath puede resolverse y permite comprobar su presencia. Un paquete que de verdad no existe produce MODULE_NOT_FOUND en ambos intentos.
Ejecuté node --test ./node-exports-resolution.test.cjs con Node.js v22.16.0 en Linux aislado y sin instalar paquetes de terceros. Este fragmento proviene de la salida TAP real de Node.js, no de un log inventado de Astro:
# OBSERVED: legacy package resolution = FOUND
# OBSERVED: package exists; require.resolve(root) = ERR_PACKAGE_PATH_NOT_EXPORTED
# OBSERVED: require.resolve(package.json) = FOUND
# OBSERVED: absent package = MODULE_NOT_FOUND in both paths
# OBSERVED: catch-all = false missing; code-aware fallback = detected installed
# tests 5
# pass 5
# fail 0
Las cinco pruebas pasaron. Lo que demuestran es un comportamiento específico de la resolución de paquetes en Node.js, no que se haya ejecutado TypeScript 7, Astro o astro check. El recurso de consultar package.json tampoco es universal: si un paquete no exporta esa ruta, también puede fallar.
Y aunque se corrija el mensaje engañoso de «paquete ausente», eso no añade por arte de magia la antigua API que falta en TypeScript 7.0. El PR #18053 de Astro, fusionado en septiembre de 2026, mejoró la explicación del error relacionado con TypeScript 7. Que se cerrase el issue correspondiente no demuestra compatibilidad completa con 7.0.
Cómo restauraría la CI en un proyecto Astro afectado
Para una combinación de versiones parecida, empezaría por averiguar qué versiones de TypeScript y @astrojs/check están realmente instaladas, qué rango peer declara el lockfile y qué error exacto aparece. Una propuesta de actualización de Dependabot no significa que toda la cadena de herramientas del framework ya sea compatible.
El proyecto del ejemplo tiene un workspace npm llamado web dentro de apps/web. Los siguientes comandos son pasos que el lector puede ejecutar en su propia rama de reparación, basados en el PR #10 público. No los ejecuté en el repositorio original:
# Inspeccionar las versiones instaladas
npm ls typescript @astrojs/check -w web
# Recuperar la versión elegida para este caso
npm install --save-dev 'typescript@^6.0.3' -w web
# Reinstalar a partir del lockfile y comprobar tipos y build
npm ci
npm run check -w web
npm run build -w web
Si ya existe un conflicto, npm ls puede terminar con un código distinto de cero; eso mismo puede servir como pista. Conviene conservar el commit original o abrir una rama específica y comprobar los requisitos reales de Node/npm y el nombre del workspace. En un paquete único se omite -w web. ^6.0.3 es la elección de este caso fijado, no una recomendación permanente para todos los proyectos Astro.
Después evitaría que la misma propuesta de actualización reapareciera automáticamente. En el .github/dependabot.yml del ejemplo se añadió esta regla temporal dentro de la configuración npm:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
ignore:
- dependency-name: typescript
versions: [">=7.0.0"]
Es importante poner ignore dentro de la entrada de npm y no bloquear actualizaciones de dependencias sin relación. También dejaría constancia de cuándo revisar la excepción: cuando Astro y sus herramientas de lenguaje soporten la nueva integración y la CI del propio proyecto pase realmente. Una solución temporal puede acabar congelando la versión para siempre si nadie define esa condición.
En el repositorio analizado, check-web incluye formateo, astro check y compilación. Una verificación útil necesita comprobar que el lockfile contiene la combinación esperada, que npm ci reproduce la instalación, que astro check sigue ejecutándose y que el build funciona. Si ya hay una fixture que provoca un error de tipos en un archivo .astro, mejor confirmar también que el checker todavía lo detecta. Un único indicador verde es poca información.
¿Se puede quitar el bloqueo cuando llegue TypeScript 7.1?
Volver temporalmente a una versión anterior no significa renunciar a la nueva arquitectura para siempre. En el anuncio de TypeScript 7.0, Microsoft habló del trabajo en una nueva API programática y de alternativas como @typescript/typescript6 para convivir con el nuevo tsc. Sin embargo, el ejecutable del compilador, el análisis de plantillas Astro, los servicios de lenguaje del editor y la comprobación de tipos en CI son pruebas de adopción diferentes.
En el momento de esta investigación, el Issue #17268 de Astro estaba cerrado y el PR #18053 con mejores mensajes de error ya estaba fusionado. El PR #17852, relacionado con enviar .astro al Content Mapper de TypeScript 7, seguía abierto. Son estados de un momento determinado; deben revisarse de nuevo tras cada nueva versión.
Si una actualización mayor rompe astro check, la secuencia razonable es revisar el error y el contrato de dependencias, conservar el checker, recuperar una combinación compatible, verificar el lockfile y la CI, y planificar la migración siguiente por separado. El objetivo no es silenciar una pipeline roja, sino recuperar la comprobación que antes protegía el proyecto.
Para saber por qué elegí Astro como base de un blog técnico, conté mis motivos en una comparación anterior de Astro, Markdown y GitHub Actions. Aquí el problema viene después de esa elección: impedir que una actualización automática de dependencias elimine sin hacer ruido una garantía de calidad existente.