Astro check non funziona con TypeScript 7: meglio correggere le dipendenze che togliere il controllo dei tipi
Una pull request di Dependabot ha aggiornato TypeScript dalla versione 6.0.3 alla 7.0.2. A guardare soltanto i numeri sembra un normale aggiornamento major. In un progetto Astro, però, può essere sufficiente a far smettere di funzionare astro check.
Esaminando una issue pubblica di un progetto Astro/Starlight, ho trovato due possibili rimedi molto diversi. Il primo eliminava astro check dalla CI, così il controllo che falliva non veniva più eseguito. Il secondo riportava TypeScript alla serie 6, conservava il checker e impediva temporaneamente a Dependabot di proporre ancora aggiornamenti alla 7.x. È stata integrata la seconda soluzione.
Non era soltanto una dichiarazione di peer dependency rimasta indietro. TypeScript 7.0 ha adottato un compilatore nativo e alcuni strumenti per i framework dipendono ancora dall’API programmatica di TypeScript 6. Nell’annuncio ufficiale di TypeScript 7.0, Microsoft consiglia esplicitamente di mantenere TypeScript 6 per le integrazioni con linguaggi incorporati, come Astro, Vue, Svelte e MDX, finché gli strumenti non avranno completato la migrazione.
Una precisazione sulle prove: ho letto le dipendenze a un commit preciso, le due PR e il run GitHub Actions del progetto originale. Ho anche eseguito personalmente cinque test sintetici con la sola libreria standard di Node.js, per capire come exports possa far sembrare assente un pacchetto già presente. Non ho eseguito npm install né astro check nel progetto Astro interessato. La CI riuscita di cui parlerò è un risultato del progetto originale, non una riproduzione indipendente fatta da me.
Due soluzioni: eliminare il controllo o ripristinare una versione compatibile
Il caso è documentato in vishwakarma Issue #8. In precedenza Dependabot PR #3 aveva aggiornato TypeScript alla 7.0.2. Il maintainer ha segnalato che con quella combinazione astro check incontrava problemi di compatibilità.
PR #9 proponeva di togliere il checker. La modifica rimuoveva lo script check e la dipendenza @astrojs/check da apps/web/package.json, eliminando anche typecheck-web dal Makefile. check-web sarebbe così rimasto limitato alla formattazione e alla build. La PR è stata chiusa senza merge.
Se smetti di eseguire il controllo che fallisce, è possibile che la CI torni verde. Ma una astro build riuscita non equivale ai controlli sui tipi che astro check esegue sui file .astro e sul codice TypeScript. In quel caso non hai risolto il problema: hai rinunciato a una verifica che prima proteggeva il progetto.
La PR #10, quella effettivamente integrata, ha mantenuto il checker e ripristinato la dipendenza TypeScript del workspace web:
- "typescript": "^7.0.2"
+ "typescript": "^6.0.3"
Nel commit pubblico fissato dopo la correzione, apps/web/package.json indica Astro ^7.2.10 e @astrojs/check ^0.9.10. Lo stesso package-lock.json blocca @astrojs/[email protected] e dichiara questo intervallo per TypeScript:
"peerDependencies": {
"typescript": "^5.0.0 || ^6.0.0"
}
È una dichiarazione letta dal lockfile, non il messaggio di un comando npm che ho eseguito personalmente. Almeno per questa versione del checker, TypeScript 7 non rientra nell’intervallo peer supportato.
Esiste anche una prova esterna dell’esecuzione dopo il fix. GitHub Actions #38103905437 ha girato sull’head della PR 5d828e8d55c5db833f5cca17f28da3b6aba05a99. Il job web, compresi make setup-web e make check-web, e il job Python sono terminati con successo. È una conferma dello stato corretto con il checker ancora presente. Non dimostra che io abbia riprodotto indipendentemente il guasto con TypeScript 7.
Come può risultare mancante un TypeScript che è già installato?
Ci sono due livelli di incompatibilità da distinguere.
Il primo è più profondo e riguarda le API del compilatore. TypeScript 7.0 è passato a un’implementazione nativa in Go. Il fatto che tsc funzioni come comando non significa che l’API programmatica stabile di TypeScript 6 sia rimasta disponibile. Astro deve analizzare TypeScript dentro i file .astro attraverso i propri servizi di linguaggio. Aggiornare il compilatore da riga di comando non completa automaticamente quell’integrazione.
Il secondo livello rischia di mandare fuori strada durante il debug. Nell’Issue #17268 di Astro è documentato come il cambiamento degli exports di TypeScript 7 possa far fallire una vecchia verifica basata su require.resolve('typescript') con ERR_PACKAGE_PATH_NOT_EXPORTED. Se il programma interpreta qualsiasi errore di risoluzione come «TypeScript non installato», mostra un suggerimento inesatto.
Ho voluto verificare soltanto questo meccanismo, senza installare tutto Astro o il vero TypeScript 7. Con la libreria standard di Node.js v22.16.0 ho creato due pacchetti simulati e temporanei: uno con il classico punto d’ingresso e uno che esporta solo ./package.json, senza esportare la radice del pacchetto. Ecco la parte importante della configurazione usata realmente, leggermente riordinata:
{
name: 'native-ts-synthetic',
version: '7.0.0-fixture',
type: 'module',
exports: {
'./package.json': './package.json'
}
}
Per questo pacchetto sintetico, require.resolve('native-ts-synthetic') produce ERR_PACKAGE_PATH_NOT_EXPORTED anche se i file sono presenti. Poiché il mock esporta esplicitamente ./package.json, la risoluzione di native-ts-synthetic/package.json funziona e permette di riconoscere il pacchetto installato. Un pacchetto davvero inesistente restituisce MODULE_NOT_FOUND in entrambi i casi.
Ho eseguito node --test ./node-exports-resolution.test.cjs in un ambiente Linux isolato con Node.js v22.16.0, senza dipendenze npm di terze parti. Questo è un estratto del vero output TAP di Node.js, non un log di errore di Astro inventato:
# 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
I cinque test sono passati, ma dimostrano uno specifico comportamento della risoluzione dei pacchetti in Node.js, non la compatibilità reale tra TypeScript 7, Astro e astro check. Nemmeno il fallback a package.json è universale: se un pacchetto non esporta quel percorso, anche questa ricerca può fallire.
Inoltre, sistemare l’individuazione dei pacchetti installati non ripristina l’API precedente assente in TypeScript 7.0. La PR #18053 di Astro, integrata a settembre 2026, ha migliorato i messaggi per gli errori con TypeScript 7. La chiusura della relativa issue non prova il supporto completo alla versione 7.0.
Come recuperare la CI in un progetto Astro interessato
Con una combinazione simile di versioni, partirei controllando le versioni effettive di TypeScript e @astrojs/check, l’intervallo peer nel lockfile e l’errore originale. Una proposta di upgrade da Dependabot non garantisce che tutti gli strumenti del framework siano già pronti.
Nel repository dell’esempio esiste un workspace npm chiamato web sotto apps/web. Questi comandi sono passi che un lettore può eseguire nel proprio branch di riparazione, ricavati dalla PR #10 pubblica. Io non li ho eseguiti nel repository originale:
# Controllare le dipendenze in uso
npm ls typescript @astrojs/check -w web
# Ripristinare la versione compatibile scelta in questo caso
npm install --save-dev 'typescript@^6.0.3' -w web
# Reinstallare dal lockfile e verificare check e build
npm ci
npm run check -w web
npm run build -w web
Se esiste già un conflitto di dipendenze, npm ls può terminare con un codice diverso da zero: è un indizio utile. Prima conserva il commit iniziale o lavora su un branch separato e controlla le versioni richieste di Node/npm e il nome del workspace. In un progetto con un singolo pacchetto, -w web non serve. ^6.0.3 è la soluzione di questo caso fissato, non una prescrizione permanente per qualunque progetto Astro.
Poi eviterei che la stessa PR di aggiornamento major riaprisse il problema. Nel .github/dependabot.yml del commit fissato compare questa regola temporanea relativa a npm:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
ignore:
- dependency-name: typescript
versions: [">=7.0.0"]
L’ignore va inserito nell’ecosistema npm corretto, senza bloccare anche gli aggiornamenti delle altre dipendenze. È opportuno annotare quando eliminarlo: quando il checker e gli strumenti di linguaggio di Astro supporteranno davvero il nuovo sistema, e quando la CI del proprio progetto lo avrà verificato. Altrimenti una soluzione provvisoria rischia di diventare un blocco delle versioni senza scadenza.
Nel progetto esaminato check-web comprende formattazione, astro check e build. Per verificare una correzione serve quindi controllare separatamente che il lockfile contenga le versioni previste, che npm ci riproduca l’installazione, che astro check venga davvero eseguito e che la build continui a riuscire. Se c’è già un test che introduce un errore di tipo in un file .astro, sarebbe ancora meglio controllare che il checker sappia rilevarlo.
TypeScript 7.1 permetterà di togliere subito il blocco?
Tornare temporaneamente a TypeScript 6 non significa rinunciare per sempre al nuovo compilatore. Nell’annuncio di TypeScript 7.0, Microsoft ha parlato del lavoro in corso su nuove API programmatiche e di opzioni come @typescript/typescript6, utili per far convivere strumenti più vecchi e il nuovo tsc. Tuttavia, il compilatore CLI, l’analisi dei template Astro, i servizi di linguaggio dell’editor e il controllo dei tipi in CI richiedono verifiche diverse.
Al momento della ricerca, l’Issue #17268 di Astro era chiusa e la PR #18053 con messaggi di errore più chiari era stata integrata. Restava aperta la PR #17852, relativa al Content Mapper di TypeScript 7 per .astro. È lo stato delle fonti in quel momento, non una garanzia su ciò che i prossimi rilasci supporteranno.
Se un upgrade major rompe astro check, la sequenza ragionevole è controllare l’errore e il contratto delle dipendenze, mantenere il checker, ripristinare una combinazione compatibile e verificare lockfile e CI. La migrazione successiva può essere pianificata come attività separata. L’obiettivo è recuperare un controllo efficace, non soltanto zittire una pipeline rossa.
Per spiegare perché avevo scelto Astro per un blog tecnico, avevo scritto una precedente analisi di Astro, Markdown e GitHub Actions. Qui il problema arriva dopo quella scelta: evitare che un aggiornamento automatico delle dipendenze rimuova senza accorgersene uno dei controlli di qualità già presenti.