TypeScript を、そのままネイティブへ。

scriptc / zero-runtime TypeScript compiler / native executable

1 — 概要

scriptc は、通常の TypeScript を小さなネイティブ実行ファイルへ変換する実験的なコンパイラです。コードに専用アノテーションや別方言を導入せず、TypeScript コンパイラによる型検査を通したあと、型付き IR とネイティブ向けバックエンドへ渡します。

静的に証明できる処理は Node.js、V8、JavaScript エンジンを含まない実行ファイルになります。静的に扱えない箇所は明示的に動的実行へ切り替えるか、診断コードと書き換えの手掛かりを伴って拒否します。

170–200KB静的バイナリの目安
約 2.4msApple M 系での起動例
1–4MB典型的な RSS
800+差分テストのコーパス

数値はプロジェクト README に掲載された Apple M シリーズ上の測定例です。ワークロード、機能、ビルド条件で変わります。

2 — 静的・動的・拒否の境界
TIER 01

静的コンパイル

既定の経路です。型と制御フローから証明できる処理をネイティブコードへ変換し、JavaScript エンジンを含めません。

TIER 02

動的アイランド

--dynamic を明示すると、npm パッケージの JavaScript や any の処理を QuickJS ベースの埋め込みエンジンで実行します。静的側へ戻る値は実行時に検証されます。

TIER 03

診断して拒否

どちらの経路でも安全に扱えない構文は、コードフレーム、固有の診断コード、多くの場合は書き換え案を示して停止します。

暗黙の切り替えはしません。 静的ビルドが勝手に JavaScript エンジンを同梱することはなく、LLVM の対応範囲外で C バックエンドへ移る場合も標準エラーへ1行の通知を出します。
3 — コンパイル経路
TypeScript入力
tsc / tsgo解析・型検査
型付き IR検証可能な境界
LLVM または Cコード生成
生成コード.ll / .c
clangコンパイル・リンク
C ランタイム必要な機能だけリンク
実行ファイル自己完結

packages/compiler

TypeScript API から IR への lowering、IR の検証と直列化、LLVM と C のコード生成を担当します。IR がフロントエンドとバックエンドの唯一の接点です。

packages/runtime

参照カウント値、循環回収、スタックフル fiber、イベントループ、ネットワーク、JS 互換の数値整形などを C で提供します。

packages/cli

build、run、coverage を公開し、出力先やバックエンド、動的実行、FFI を制御します。

4 — どこまでコンパイルするか
領域代表的な対応実装上の考え方
TypeScriptクラス、クロージャ、ジェネリクス、判別可能な Union、例外、分割代入、async / awaitTypeScript 自身の型検査と絞り込みを利用し、IR へ lower します。
標準ライブラリString、Array、Map、Set、JSON、Math、TypedArray、Buffer、正規表現UTF-16、列挙順、同一性など JavaScript の観測可能な意味を維持します。
Node APIfs、path、process、child_process、crypto、net、http、https、tls、dns、timersネイティブ実装を必要な機能単位でリンクします。
Web APIfetch、Streams、Headers、AbortSignal同じネイティブのネットワーク / TLS 層を利用し、libcurl には依存しません。
拡張境界comptime、ネイティブ FFI、--dynamic、検証付き castビルド時、C ABI、動的 JS、実行時検証の境界をそれぞれ明示します。
5 — CLI の使い方
npm install -g scriptc

scriptc run fib.ts
scriptc build fib.ts
scriptc coverage app.ts
コマンド目的主な出力
scriptc build file.tsネイティブ実行ファイルを作る.scriptc/<name> と生成した .ll または .c
scriptc run file.tsビルド後、そのまま実行する対象プログラムの標準出力・終了コード
scriptc coverage file.ts静的にコンパイルできる割合と阻害要因を調べる文単位の集計、診断コード、ブロッカー
前提: グローバル CLI のインストールには npm を使い、ネイティブビルドには clang が必要です。主対象は macOS arm64。Linux と Windows はクロスコンパイルと個別の差分テストレーンで検証されています。
6 — 正しさをどう確かめるか

Node との差分テスト

各コーパスを Node と scriptc のネイティブ実行ファイルで動かし、標準出力、標準エラー、終了コードをバイト単位で比較します。サーバー機能は両実装へ同じクライアントを接続して検証します。

メモリ安全性レーン

同じコーパスを AddressSanitizer と参照カウント監査つきで再実行し、リークや use-after-free をビルド失敗として扱います。

明示された相違

タイミング内部や Error オブジェクトの一部プロパティなど、Node と意図的に異なる箇所は番号を付けて文書化します。

開発時の合格条件

通常レーンと ASan / 参照カウント監査レーンの両方が通ることを変更の出荷条件とし、新機能には Node とネイティブの挙動を固定するコーパスを追加します。