DIEGO CECATO / NOTE DAL CAMPO

TypeScript in Rust: il benchmark non basta

diego cecato//
TypeScript in Rust: il benchmark non basta, copertina geometrica Diego Cecato

Un compilatore che impiega un secondo invece di otto è una bella notizia. Un compilatore che impiega un secondo ma segnala un errore diverso, ne omette uno o cambia il comportamento di una pipeline è un problema che hai appena reso otto volte più veloce. Il punto non è ridimensionare le prestazioni: è capire quale contratto debba rispettare lo strumento prima di affidargli una build.

Il 20 ottobre 2026 Cloudflare ha presentato tsrs, un port in Rust del compilatore TypeScript sviluppato con VoidZero e Max Schwenk, incubato nell’ecosistema Oxc e portato avanti in collaborazione con il team TypeScript. La notizia è interessante, ma la domanda utile per chi mantiene software non è quale linguaggio vincerà la gara di velocità. È se possiamo cambiare motore senza cambiare il significato delle risposte.

Prima di confrontare i numeri, confrontiamo i prodotti

TypeScript 7 non è più il vecchio compilatore scritto in TypeScript ed eseguito attraverso JavaScript. Dal luglio 2026 il rilascio ufficiale usa un port nativo in Go. Microsoft ha pubblicato il rilascio di TypeScript 7 spiegando che l’obiettivo del port era conservare struttura e semantica della versione precedente, sfruttando esecuzione nativa e parallelismo. I numeri di quel passaggio, spesso indicati come miglioramenti nell’ordine di grandezza rispetto a TypeScript 6, descrivono un confronto diverso da quello che oggi interessa tsrs.

Il progetto tsrs su Oxc prova a replicare il compilatore e il language server di TypeScript 7 in Rust. Non propone un nuovo dialetto del linguaggio, né rivendica il diritto di deciderne l’evoluzione. Cloudflare chiarisce che la responsabilità delle scelte semantiche resta al team TypeScript. Questa distinzione conta: due implementazioni possono competere sull’efficienza, ma non dovrebbero competere sul significato del codice.

Otto volte più veloce rispetto a cosa?

Cloudflare dichiara nei propri benchmark iniziali prestazioni fino a 8 volte superiori e circa il 70% di memoria in meno rispetto a TypeScript 7.0, a parità di numero di worker dedicati al type checking. È un risultato dichiarato dagli autori del progetto, non una misurazione indipendente effettuata qui. La stessa comunicazione segnala inoltre miglioramenti già presenti nella beta di TypeScript 7.1, che nei loro test arriva fino a 2,5 volte la velocità di 7.0. Il bersaglio del confronto, quindi, non è fermo.

Il dettaglio sulla configurazione è meno spettacolare del numero grande, ma è quello che rende un benchmark discutibile in modo serio. Numero di worker, dimensione della macchina, memoria di picco, cache, versione del compilatore, dimensione della codebase e modalità di compilazione cambiano il risultato. tsrs offre anche una configurazione adattiva che può impiegare più memoria per guadagnare ulteriore velocità: confrontarla con un altro compilatore configurato diversamente significa misurare anche le politiche di allocazione, non soltanto l’implementazione.

Per chi deve scegliere una toolchain, la domanda pratica è: quanto tempo risparmia una pipeline completa sul nostro repository, con i nostri errori, il nostro editor e i nostri limiti di memoria? Se il type checking pesa poco nel tempo totale di CI, moltiplicare la velocità del solo checker non moltiplica automaticamente la velocità della consegna. E se il consumo di memoria varia con i worker, il dato aggregato deve essere letto insieme al parallelismo.

Il benchmark misura quanto velocemente una macchina arriva a una risposta. La compatibilità misura se quella risposta è ancora quella che il progetto si aspetta.

Il contratto più difficile è quello degli errori

Chi non lavora quotidianamente con un compilatore tende a pensare che la compatibilità significhi soprattutto produrre lo stesso JavaScript quando il sorgente è valido. Per un type checker non basta. Conta anche quali errori vengono riconosciuti, dove sono localizzati, in che ordine compaiono, come si comportano gli strumenti che li consumano e se i codici diagnostici restano utilizzabili da script e integrazioni.

Il repository di tsrs dichiara come obiettivo la piena conformità e colloca una versione stabile allineata a TypeScript 7.1 nel percorso previsto. Non presenta però quel traguardo come già certificato. Documenta differenze note nell’ordine dei diagnostici, influenzate anche dalla concorrenza del compilatore Go usato per il confronto, e propone opzioni come --checkerAssignment go --noLazyMembers per avvicinare le condizioni di verifica. Inoltre, al momento della pubblicazione del repository, le opzioni --init e --showConfig non sono supportate.

Non tutte queste differenze sono bug semantici. L’ordine di due errori, per esempio, potrebbe non cambiare il risultato del controllo dei tipi; può comunque cambiare snapshot test, log, parser di diagnostici o flussi automatizzati che presumono una sequenza stabile. È proprio qui che il criterio deve diventare più preciso: distinguere incompatibilità che alterano la correttezza, differenze osservabili ma accettabili e funzionalità non ancora disponibili.

La conformità non è un interruttore acceso o spento

Un test differenziale utile esegue gli stessi sorgenti con due implementazioni, normalizza soltanto ciò che è lecito normalizzare e confronta esiti, codici di errore, posizioni, output e comportamento delle opzioni rilevanti. Se si normalizza troppo, si nascondono regressioni; se non si normalizza nulla, si rischia di chiamare bug ogni differenza di ordinamento. Serve un contratto esplicito, versionato e ripetibile, non un’impressione ricavata da qualche progetto dimostrativo.

Il port non finisce quando il codice compila

C’è poi il problema che raramente trova spazio nei titoli: TypeScript continua a evolvere. Un port fedele deve inseguire cambiamenti nel parser, nella risoluzione dei moduli, nel sistema dei tipi, nei diagnostici e negli strumenti che ruotano attorno al linguaggio. Cloudflare spiega di voler adottare un processo continuo di sincronizzazione con upstream, test di compatibilità e segnalazione delle differenze. È una strategia sensata, ma resta un impegno di manutenzione da dimostrare nel tempo.

La stessa iniziativa prevede di unificare il lavoro con tsc-rs per coprire funzionalità come il Language Server Protocol e i content mapper. Anche questo è un promemoria importante: sostituire il comando di compilazione non equivale a sostituire tutte le interazioni che un IDE, un plugin o un sistema di analisi statica hanno con il compilatore. Le API e le integrazioni sono parte del prodotto, anche quando non compaiono nei benchmark.

È una dinamica che vale ben oltre TypeScript. Ne avevo affrontato un altro lato ragionando sul costo nascosto della manutenzione open source: l’adozione di uno strumento non si esaurisce con il suo download. E la questione della correttezza del compilatore emerge anche quando si osserva una regressione del compilatore Rust sul confine ABI. In entrambi i casi, il problema non è la velocità con cui il codice viene prodotto, ma la fiducia che possiamo riporre nel suo comportamento.

Rust e WebAssembly: qui il vantaggio non è soltanto cronometrare

Ridurre tsrs a una gara Rust contro Go sarebbe superficiale. Cloudflare indica un altro motivo concreto per esplorare Rust: la possibilità di distribuire il checker anche in ambienti WebAssembly, con vincoli differenti da quelli di una macchina di sviluppo tradizionale. Il repository documenta un pacchetto @tsrs/wasm con target WASI Preview 1. Questo apre scenari interessanti per toolchain isolate, ambienti nel browser e processi che devono limitare risorse e privilegi.

Non significa che ogni browser possa improvvisamente eseguire l’intera esperienza TypeScript senza compromessi, né che la disponibilità di un target WASM garantisca automaticamente parità funzionale con gli eseguibili nativi. Significa che la forma di distribuzione diventa una variabile architetturale. Se un checker può stare dentro un sandbox con budget prevedibile, la prestazione è solo una parte del vantaggio: contano isolamento, portabilità, integrazione e manutenzione del runtime.

Come lo proverei prima di cambiare la pipeline

Il modo più ragionevole di valutare tsrs oggi è affiancarlo, non sostituire di colpo il compilatore ufficiale. La prova deve partire da una baseline registrata, non da una sensazione di maggiore reattività. È un esperimento a basso rischio se non si permette al risultato del nuovo checker di decidere da solo il rilascio.

  • Fissare versioni, commit, sistema operativo, hardware e numero di worker; usare lo stesso insieme di progetti e ripetere le misure a cache fredda e calda.
  • Eseguire il checker ufficiale e tsrs sugli stessi sorgenti, salvando exit code, codici diagnostici, posizioni e output. Classificare le differenze invece di cancellarle dai log.
  • Separare tempi di type checking, build completa, avvio dell’editor e consumo di memoria. Non sommare metriche incompatibili in un unico numero.
  • Provare esplicitamente le opzioni di configurazione e le integrazioni davvero usate dal progetto; una feature non supportata può rendere irrilevante un grande speedup.
  • Tenere inizialmente tsrs in modalità osservativa nella CI e promuoverlo solo quando la matrice di conformità del repository è soddisfatta e le differenze residue sono comprese.

Non è burocrazia applicata allo sviluppo. È il modo per non trasformare un’ottimizzazione locale in una nuova classe di incidenti difficili da diagnosticare. Un checker che segnala più rapidamente gli stessi problemi ha valore. Uno che segnala problemi diversi può avere comunque valore sperimentale, ma richiede una decisione consapevole, non un aggiornamento automatico.

La domanda da fare tra sei mesi

Il risultato più interessante non sarà stabilire se Rust batte Go su un grafico del giorno del lancio. Sarà verificare se, dopo mesi di evoluzione di TypeScript, il port mantiene diagnostici e integrazioni coerenti, riesce a incorporare le correzioni upstream e conserva vantaggi misurabili su progetti reali. Il progetto è promettente proprio perché rende questa domanda verificabile con codice, test e un repository pubblico.

Nel frattempo, la lezione per chi progetta sistemi è abbastanza semplice: la performance è una proprietà del sistema, non uno slogan del singolo componente. E quando quel componente interpreta il nostro codice, la prima prestazione da pretendere è la correttezza della risposta. Il cronometro viene subito dopo.

Domande frequenti

Che cos'è tsrs e che rapporto ha con TypeScript 7?

tsrs è un port sperimentale in Rust del compilatore e del language server di TypeScript 7, sviluppato nell’ecosistema Oxc con Cloudflare e VoidZero. Non è un nuovo linguaggio: l’obiettivo dichiarato è riprodurre la semantica stabilita dal team TypeScript.

tsrs è davvero otto volte più veloce di TypeScript?

Cloudflare dichiara benchmark iniziali fino a 8 volte più veloci e circa il 70% di memoria in meno rispetto a TypeScript 7.0, a parità di worker. Sono misure degli autori, non una garanzia per ogni progetto: hardware, configurazione, codebase e versioni influenzano i risultati.

tsrs è già compatibile al 100% con TypeScript?

No: il repository indica la conformità completa come obiettivo di una release stabile legata a TypeScript 7.1. Sono documentate differenze nell’ordine dei diagnostici e l’assenza di alcune opzioni, tra cui –init e –showConfig.

Come posso valutare tsrs senza rischiare regressioni nella CI?

Esegui tsrs in parallelo al compilatore ufficiale, con versioni e numero di worker fissati. Confronta exit code, codici diagnostici, posizioni, output e memoria su progetti reali; classifica le differenze e non rendere inizialmente tsrs il controllo che blocca o autorizza il rilascio.