La pipeline, passo dopo passo
- 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.
- 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.
- 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. - 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.
- 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.