Un compilatore nativo per TypeScript, costruito in Rust

Perry compila il TypeScript che già scrivi in codice macchina — nello stesso modo in cui una toolchain Rust o Go compila il proprio linguaggio. Niente JavaScript transpilato, nessuna macchina virtuale, nessun runtime sul sistema di destinazione.

Non un transpiler. Non un runtime.

La maggior parte degli strumenti TypeScript rientra in due famiglie. I transpiler — tsc, SWC, esbuild — controllano e rimuovono i tipi, poi emettono JavaScript che un motore eseguirà in seguito. I runtime — Node.js, Bun, Deno — sono quei motori: analizzano, interpretano e compilano JIT il JavaScript ogni volta che il tuo programma si avvia.

Un compilatore nativo è la terza famiglia, e per TypeScript è rimasta perlopiù vuota. Perry tratta le annotazioni di tipo non come documentazione da rimuovere ma come l'input che guida la generazione del codice. Il risultato di perry compile main.ts è un eseguibile standalone contenente codice macchina — tipicamente da 2–5 MB, con avvio in circa un millisecondo.

Come funziona

Dal codice sorgente TypeScript all'eseguibile nativo in pochi secondi

TypeScriptFile .ts
SWC
ParserParsing veloce
HIR
TrasformazioneMonomorphization
LLVM
CodegenCodice macchina
EseguibileBinario da 2-5 MB

Vuoi sapere come funziona il compilatore sotto il cofano? Meccanismi interni del compilatore

Approfondimento: TypeScript su LLVM — monomorfizzazione, NaN-boxing e perché Perry ha abbandonato Cranelift.

La pipeline, passo dopo passo

  1. Parsing (SWC). I file sorgente vengono analizzati con SWC, il parser TypeScript nativo in Rust, così anche i progetti di grandi dimensioni vengono analizzati in millisecondi. La codegen dei moduli, i passaggi di trasformazione e la scansione dei simboli vengono eseguiti in parallelo su tutti i core.
  2. Risoluzione dei tipi. Il compilatore risolve i tipi dichiarati e deduce il resto, assegnando a ogni espressione un tipo concreto prima che inizi la generazione del codice.
  3. HIR tipizzato e monomorfizzazione. L'AST viene sottoposto a lowering in un IR tipizzato di alto livello. Le funzioni e le classi generiche vengono monomorfizzate — ogni istanziazione come Stack<number> viene compilata separatamente con i suoi tipi concreti, quindi i generici non costano nulla a runtime. Dove i tipi sono noti, le chiamate ai metodi diventano dispatch statico e i campi degli oggetti diventano load diretti a offset fisso.
  4. Codegen (LLVM). L'HIR viene abbassato a LLVM IR e fatto passare attraverso la pipeline di ottimizzazione di LLVM — inlining, ottimizzazioni dei cicli, vettorizzazione — poi emesso come codice macchina per il target.
  5. Link. L'output è un normale eseguibile di piattaforma: Mach-O su macOS, ELF su Linux, PE su Windows — oltre ai target mobile, watch, TV e WebAssembly.

Il lato LLVM di tutto questo — perché LLVM è stato scelto al posto di Cranelift, come il NaN-boxing rappresenta i valori dinamici, cosa fa l'ottimizzatore con l'IR tipizzato — ha un proprio approfondimento: TypeScript su LLVM. I dettagli implementativi come NaN-boxing, dispatch statico e astrazioni a costo zero sono trattati nei meccanismi interni del compilatore.

E il codice dinamico e npm?

Sotto il cofano, TypeScript è comunque JavaScript, e un compilatore nativo per TypeScript deve essere onesto su questo. La conformità di Perry rispetto alla suite ufficiale test262 è misurata e pubblicata — a partire dalla v0.5.1146, la semantica String è al 79% e Array al 72%, entrambe in crescita release dopo release. I pacchetti npm TypeScript/JavaScript puro compilano nativamente tramite perry.compilePackages: axios, zod v4, express, fastify e hono compilano e funzionano già oggi. Il codice che necessita della piena semantica del motore può optare per un fallback V8 embedded con --enable-js-runtime.

La storia completa è in Veri pacchetti npm ora compilano: axios, zod, express — e una passata di conformance.

Come Perry si colloca rispetto ad altri sforzi di “TypeScript nativo”

Perry non è l'unico progetto ad aver guardato alle annotazioni di tipo di TypeScript vedendoci un'opportunità di compilazione — ma gli approcci differiscono nettamente. AssemblyScript compila un linguaggio rigoroso simil-TypeScript solo verso WebAssembly: è deliberatamente non compatibile con JavaScript, e non produce eseguibili per il sistema operativo né UI native. Static Hermes di Meta compila ahead-of-time un sottoinsieme JavaScript tipizzato all'interno del motore Hermes, principalmente per React Native — a metà 2026 resta un progetto di ricerca che deve essere compilato dai sorgenti, e il motore Hermes V1 effettivamente distribuito in React Native non include le funzionalità statiche (confronto completo).

La scommessa di Perry è diversa su entrambi gli assi: TypeScript standard come linguaggio di input, ed eseguibili di piattaforma ordinari — CLI, server e GUI — come output, installabili oggi tramite Homebrew, APT, winget o npm.

Un compilatore, dieci target

Poiché la generazione del codice passa attraverso LLVM, un'unica codebase compila per macOS, iOS, iPadOS, Android, Linux, Windows, watchOS, tvOS, WebAssembly e il semplice Web/JS — incluso il cross-compiling di binari Windows, macOS e iOS da una macchina Linux. Le app GUI usano perry/ui, un'API dichiarativa sopra veri widget di piattaforma (AppKit, UIKit, GTK4, Win32, Android tramite JNI) — senza alcuna webview coinvolta.

Come si confronta con altri approcci: Perry vs Bun, Deno, Electron, Tauri, React Native e Static Hermes.

Prova il compilatore

Installa Perry e compila il tuo primo binario nativo in meno di un minuto.