Một trình biên dịch TypeScript gốc, được xây dựng bằng Rust

Perry biên dịch chính TypeScript bạn đang viết thành mã máy — theo cách một toolchain Rust hay Go biên dịch ngôn ngữ của nó. Không có JavaScript transpile, không có máy ảo, không có runtime trên hệ thống đích.

Không phải transpiler. Không phải runtime.

Phần lớn công cụ TypeScript rơi vào hai nhóm. Transpiler — tsc, SWC, esbuild — kiểm tra rồi loại bỏ kiểu, sau đó sinh ra JavaScript để một engine thực thi sau này. Runtime — Node.js, Bun, Deno — chính là những engine đó: chúng parse, thông dịch và biên dịch JIT JavaScript mỗi lần chương trình của bạn khởi động.

Trình biên dịch gốc là nhóm thứ ba, và với TypeScript nhóm này gần như còn bỏ trống. Perry coi chú thích kiểu không phải là tài liệu để loại bỏ mà là đầu vào dẫn dắt việc sinh mã. Kết quả của perry compile main.ts là một tệp thực thi độc lập chứa mã máy — thường 2–5 MB, khởi động trong khoảng một mili giây.

Cách hoạt động

Từ mã nguồn TypeScript đến tệp thực thi gốc chỉ trong vài giây

TypeScriptTệp .ts
SWC
Bộ phân tíchPhân tích nhanh
HIR
Chuyển đổiMonomorphization
LLVM
Sinh mãMã máy
Tệp thực thiBinary 2-5 MB

Muốn biết trình biên dịch hoạt động bên trong như thế nào? Cấu trúc bên trong trình biên dịch

Tìm hiểu chuyên sâu: TypeScript trên LLVM — monomorphization, NaN-boxing, và lý do Perry rời bỏ Cranelift.

Pipeline, từng bước một

  1. Parse (SWC). Tệp nguồn được parse bằng SWC, trình phân tích cú pháp TypeScript viết bằng Rust, nên ngay cả dự án lớn cũng được parse trong vài mili giây. Sinh mã module, các transform pass và quét symbol chạy song song trên nhiều lõi.
  2. Giải quyết kiểu. Trình biên dịch giải quyết các kiểu đã khai báo và suy luận phần còn lại, gán cho mỗi biểu thức một kiểu cụ thể trước khi việc sinh mã bắt đầu.
  3. HIR có kiểu & monomorphization. AST được hạ cấp thành một IR bậc cao có kiểu (HIR). Hàm và lớp generic được monomorphize — mỗi lần khởi tạo như Stack<number> được biên dịch riêng với kiểu cụ thể của nó, nên generic không tốn chi phí gì lúc runtime. Khi kiểu đã biết, lệnh gọi phương thức trở thành static dispatch và trường đối tượng trở thành phép đọc trực tiếp với offset cố định.
  4. Sinh mã (LLVM). HIR được hạ cấp thành LLVM IR và chạy qua pipeline tối ưu hóa của LLVM — inlining, tối ưu hóa vòng lặp, vector hóa — rồi được xuất thành mã máy cho mục tiêu.
  5. Liên kết. Đầu ra là một tệp thực thi nền tảng bình thường: Mach-O trên macOS, ELF trên Linux, PE trên Windows — cộng với các mục tiêu di động, watch, TV và WebAssembly.

Phần liên quan đến LLVM — tại sao LLVM được chọn thay vì Cranelift, NaN-boxing biểu diễn giá trị động ra sao, trình tối ưu hóa làm gì với IR có kiểu — có bài tìm hiểu chuyên sâu riêng: TypeScript trên LLVM. Chi tiết triển khai như NaN-boxing, static dispatch và zero-cost abstraction được trình bày trong cấu trúc bên trong trình biên dịch.

Còn mã động và npm thì sao?

TypeScript về bản chất vẫn là JavaScript, và một trình biên dịch TypeScript gốc phải thẳng thắn thừa nhận điều đó. Độ tuân thủ của Perry với bộ test262 chính thức được đo lường và công bố — tính đến v0.5.1146, ngữ nghĩa String đạt 79% và Array đạt 72%, cả hai đều tăng dần qua từng bản phát hành. Các gói npm TypeScript/JavaScript thuần biên dịch gốc qua perry.compilePackages: axios, zod v4, express, fastify và hono đã có thể biên dịch và chạy ngay hôm nay. Mã cần đầy đủ ngữ nghĩa engine có thể dùng tùy chọn V8 nhúng dự phòng với --enable-js-runtime.

Câu chuyện đầy đủ nằm trong Các package npm thực tế và một lượt quét conformance.

Perry liên hệ thế nào với các nỗ lực “TypeScript gốc” khác

Perry không phải là dự án duy nhất nhìn vào chú thích kiểu của TypeScript và thấy một cơ hội biên dịch — nhưng cách tiếp cận khác nhau rất nhiều. AssemblyScript chỉ biên dịch một ngôn ngữ giống TypeScript nghiêm ngặt sang WebAssembly: nó cố tình không tương thích JavaScript, và không tạo ra tệp thực thi hệ điều hành hay UI gốc. Static Hermes của Meta biên dịch ahead-of-time một tập con JavaScript có kiểu bên trong engine Hermes, chủ yếu cho React Native — tính đến giữa năm 2026 nó vẫn là một dự án nghiên cứu phải được build từ mã nguồn, và engine Hermes V1 thực sự được đưa vào React Native không bao gồm các tính năng biên dịch tĩnh (so sánh đầy đủ).

Canh bạc của Perry khác biệt trên cả hai trục: TypeScript chuẩn làm ngôn ngữ đầu vào, và các tệp thực thi nền tảng thông thường — CLI, server và GUI — làm đầu ra, có thể cài đặt ngay hôm nay qua Homebrew, APT, winget hoặc npm.

Một trình biên dịch, mười mục tiêu

Vì việc sinh mã đi qua LLVM, một mã nguồn duy nhất biên dịch được sang macOS, iOS, iPadOS, Android, Linux, Windows, watchOS, tvOS, WebAssembly và Web/JS thuần — bao gồm cả biên dịch chéo binary Windows, macOS và iOS từ một máy Linux. Ứng dụng GUI sử dụng perry/ui, một API khai báo trên các widget nền tảng thực sự (AppKit, UIKit, GTK4, Win32, Android qua JNI) — không có webview nào liên quan.

So sánh với các cách tiếp cận khác thế nào: Perry vs Bun, Deno, Electron, Tauri, React Native và Static Hermes.

Dùng thử trình biên dịch

Cài đặt Perry và biên dịch binary gốc đầu tiên của bạn trong chưa đầy một phút.