TypeScript ネイティブコンパイラ、 Rust で構築

Perry は、あなたが今書いている TypeScript をマシンコードへ コンパイルします——Rust や Go のツールチェーンが自らの言語を コンパイルするのと同じやり方です。トランスパイルされた JavaScript も、仮想マシンも、ターゲットシステム上のランタイム も不要です。

トランスパイラではなく、ランタイムでもない。

ほとんどの TypeScript ツールは2つの系統に分かれます。トランス パイラ——tsc、SWC、 esbuild——は型をチェックして取り除き、あとでエンジンが実行する ための JavaScript を出力します。ランタイム——Node.js、Bun、 Deno——はそのエンジンそのものです。プログラムが起動するたびに JavaScript をパースし、解釈し、JIT コンパイルします。

ネイティブコンパイラは3つ目の系統であり、TypeScript においては これまでほぼ空白でした。Perry は型注釈を、取り除かれるべき ドキュメントとしてではなく、コード生成を駆動する入力として 扱います。perry compile main.ts の結果は、マシンコードを含むスタンドアロンの実行ファイルです—— 通常2–5 MB、起動は約1ミリ秒です。

仕組み

TypeScriptソースからネイティブ実行ファイルまで、わずか数秒

TypeScript.tsファイル
SWC
パーサー高速パース
HIR
変換Monomorphization
LLVM
コード生成マシンコード
実行ファイル2〜5 MBバイナリ

コンパイラの内部の仕組みを知りたいですか? コンパイラ内部構造

深掘り:LLVM 上の TypeScript――単相化、NaN-boxing、そして Perry が Cranelift を離れた理由。

パイプラインを、段階ごとに

  1. パース(SWC)。 ソースファイルは Rust ネイティブの TypeScript パーサーである SWC でパースされるため、大きなプロジェクトでもミリ秒単位で パースが終わります。モジュールのコード生成、変換パス、 シンボルスキャンはすべて複数コアにまたがって並列に実行され ます。
  2. 型解決。 コンパイラは宣言された型を解決し、残りを推論することで、コード 生成が始まる前にすべての式に具体的な型を与えます。
  3. 型付き HIR と単相化。 AST は型付きの高レベル IR へと下げられます。ジェネリックな 関数やクラスは単相化されます——Stack<number> のようなインスタンス化はそれぞれ具体的な型で個別にコンパイル されるため、ジェネリクスは実行時に一切コストがかかりません。 型が判明している箇所では、メソッド呼び出しは静的ディスパッチ になり、オブジェクトのフィールドは直接的な固定オフセット ロードになります。
  4. コード生成(LLVM)。 HIR は LLVM IR へと下げられ、インライン化、ループ最適化、 ベクトル化といった LLVM の最適化パイプラインを通過したのち、 ターゲット向けのマシンコードとして出力されます。
  5. リンク。 出力されるのは通常のプラットフォーム実行ファイルです: macOS では Mach-O、Linux では ELF、Windows では PE—— 加えてモバイル、ウォッチ、TV、WebAssembly の各ターゲットも あります。

このうち LLVM に関わる部分——なぜ Cranelift ではなく LLVM が 選ばれたのか、NaN-boxing がどのように動的な値を表現するのか、 オプティマイザが型付き IR に対して何を行うのか——には専用の 深掘り記事があります:LLVM 上の TypeScript。NaN-boxing、静的ディスパッチ、ゼロコスト抽象化といった実装の 詳細はコンパイラ内部構造で解説しています。

動的なコードや npm はどうなるのか?

TypeScript は根底では依然として JavaScript であり、ネイティブ な TypeScript コンパイラはその点について正直でなければなり ません。Perry の test262 公式スイートに対する準拠度は計測・ 公開されています——v0.5.1146 時点で、String のセマンティクスは 79%、Array は72%で、いずれもリリースを重ねるごとに上昇して います。純粋な TypeScript / JavaScript の npm パッケージはperry.compilePackages を通じてネイティブにコンパイルされます:axios、zod v4、 express、fastify、hono は今日時点でコンパイルして実行できます。 完全なエンジンセマンティクスを必要とするコードは、--enable-js-runtime で組み込み V8 フォールバックを利用できます。

詳しい経緯はReal npm packages and a conformance sweepにまとめています。

他の“ネイティブ TypeScript”の取り組みとの関係

TypeScript の型注釈にコンパイルの可能性を見出したのは Perry だけではありません——ただし、そのアプローチは大きく異なります。 AssemblyScript は厳格な TypeScript ライクな言語を WebAssembly のみへコンパイルします:意図的に JavaScript とは互換性がなく、 OS の実行ファイルもネイティブ UI も生成しません。Meta の Static Hermes は、主に React Native 向けに、型付き JavaScript サブセットを Hermes エンジン内で事前コンパイル します——2026年半ば時点では依然としてソースからのビルドが 必要な研究プロジェクトであり、実際に React Native に出荷 された Hermes V1 エンジンには静的コンパイル機能は含まれて いません(詳細な比較)。

Perry の賭けはどちらの軸でも異なります。標準的な TypeScript を入力言語とし、CLI、サーバー、GUI といった通常のプラット フォーム実行ファイルを出力とすること——それは Homebrew、 APT、winget、npm を通じて今日インストールできます。

1つのコンパイラ、10のターゲット

コード生成が LLVM を経由するため、1つのコードベースが macOS、iOS、iPadOS、Android、Linux、Windows、watchOS、tvOS、 WebAssembly、そして通常の Web/JS にコンパイルされます—— Linux マシンから Windows、macOS、iOS 向けバイナリをクロス コンパイルすることも含まれます。GUI アプリはperry/ui を使用します。これは本物のプラットフォームウィジェット (AppKit、UIKit、GTK4、Win32、JNI 経由の Android)の上に 構築された宣言的な API であり、webview は一切関与しません。

他のアプローチと比べてどうなのか:Perry vs Bun、Deno、Electron、Tauri、React Native、Static Hermes

コンパイラを試してみよう

Perry をインストールして、1分足らずで最初のネイティブバイナリ をコンパイルしましょう。