scriptcはTypeScriptをNodeなしのネイティブへ変換する
TypeScript からネイティブへのコンパイラ。注釈や方言はなく、Node 上で実行するのと同じ TypeScript が、実際の TypeScript コンパイラによって型チェックされ、ネイティブにコンパイルされます。
ひと目でわかる
- これは何?
- TypeScriptの型検査を使い、IR、C、LLVM、アセンブリ、オブジェクト、実行ファイル、WASI向けWebAssemblyまで出力する実験的コンパイラーです。
- 誰に向いている?
- 小さなCLIやサーバーをTypeScriptで書き、配布先にNode.jsを置きたくない開発者に向きます。実験的なため、npm依存やanyを含むコードが静的に通るとは考えないでください。
- 商用利用できる?
- できます。Apache-2.0 は寛容なライセンスで、著作権表示とライセンス表示を残せば、使用・改変・販売が可能です。
- 今もメンテナンスされている?
- されています。最後のコミットは 1 日前です。
- 何の言語で書かれている?
- 主に TypeScript です(GitHub の言語統計による)。
回答はプロジェクトの GitHub データ(最終同期:2026年9月14日)と当サイトの分析に基づくもので、法的助言ではありません。
オープンソース詳細解説
TypeScriptから複数の成果物へ
scriptcはTypeScriptとJavaScriptをtyped IR、読みやすいC、LLVM IR、ネイティブアセンブリ、オブジェクト、実行ファイル、WASI Preview 1のWebAssemblyへ変換します。解析と型検査には本物のTypeScript compilerを使います。通常の静的実行ファイルにはNodeやJavaScriptエンジンが入りません。READMEの「実験的」という位置づけを維持し、言語全体を置き換える製品とは扱いません。
scriptcでは、同じhello.tsをNode、scriptc run、scriptc buildで実行し、stdout、stderr、終了コードを比較します。coverageの診断コード、.scriptc内のir、c、llvm、asm、obj、--dynamicで埋め込まれた依存を個別に確認します。WASIでは未対応APIがSC3002になることもテストに含めます。 第1章では、TypeScriptから複数の成果物へに関係する入力、出力、エラーを分けて記録します。READMEが説明していない挙動は未確認として残し、成功した一回だけを互換性の根拠にはしません。
coverageで静的範囲を可視化する
scriptc coverageは解析したstatement数、静的にコンパイルできる数、動的または未対応の箇所をコード付きで出します。静的に拒否された部分を黙って別の意味へ変換しないことが設計上の要点です。npmパッケージやany型には--dynamicを指定でき、quickjs-ngを明示的に埋め込みます。coverageの結果をCIに保存し、依存更新で動的部分が増えていないか比較します。
scriptcでは、同じhello.tsをNode、scriptc run、scriptc buildで実行し、stdout、stderr、終了コードを比較します。coverageの診断コード、.scriptc内のir、c、llvm、asm、obj、--dynamicで埋め込まれた依存を個別に確認します。WASIでは未対応APIがSC3002になることもテストに含めます。 第2章では、coverageで静的範囲を可視化するに関係する入力、出力、エラーを分けて記録します。READMEが説明していない挙動は未確認として残し、成功した一回だけを互換性の根拠にはしません。
Node APIと動的依存
READMEの例ではnode:httpのcreateServerをネイティブ実行ファイルへビルドできます。fs、path、process、child_process、os、crypto、url、zlib、タイマー、net、http、https、tlsなどのNode APIも対象として列挙されています。npm依存のJavaScriptは--dynamicでビルド時に埋め込まれ、実行時にnode_modulesを読みません。一方、静的に扱えないコードは診断になるため、coverageで境界を先に確認します。
scriptcでは、同じhello.tsをNode、scriptc run、scriptc buildで実行し、stdout、stderr、終了コードを比較します。coverageの診断コード、.scriptc内のir、c、llvm、asm、obj、--dynamicで埋め込まれた依存を個別に確認します。WASIでは未対応APIがSC3002になることもテストに含めます。 第3章では、Node APIと動的依存に関係する入力、出力、エラーを分けて記録します。READMEが説明していない挙動は未確認として残し、成功した一回だけを互換性の根拠にはしません。
出力形式とリンクの注意
--emit=ir、c、llvmはNodeだけで生成できます。macOS 15以上のarm64ではasmとobjに付属helperを使えますが、実行ファイルにはlinker driverとSDKが必要です。--emit=objは自己完結ライブラリではなくscr_*参照を持つ再配置可能オブジェクトです。外部リンクには--print=native-link-infoの版付きJSONレシピを使います。library用途は--libの経路と混同しません。
scriptcでは、同じhello.tsをNode、scriptc run、scriptc buildで実行し、stdout、stderr、終了コードを比較します。coverageの診断コード、.scriptc内のir、c、llvm、asm、obj、--dynamicで埋め込まれた依存を個別に確認します。WASIでは未対応APIがSC3002になることもテストに含めます。 第4章では、出力形式とリンクの注意に関係する入力、出力、エラーを分けて記録します。READMEが説明していない挙動は未確認として残し、成功した一回だけを互換性の根拠にはしません。
WASIと使えない機能
WASI向けビルドにはZigとSCRIPTC_TARGET=wasm32-wasiが必要です。async/await、promise、generator、timer、stdin、filesystem APIは対象に含まれますが、network socket、fetch、child process、OS signal、filesystem watching、native FFIなどはポータブルWASIの境界でSC3002などの診断になります。hello.wasmをfileで確認するだけでなく、対象ランタイムで起動し、未対応APIがリンク前に拒否されることも確認します。
scriptcでは、同じhello.tsをNode、scriptc run、scriptc buildで実行し、stdout、stderr、終了コードを比較します。coverageの診断コード、.scriptc内のir、c、llvm、asm、obj、--dynamicで埋め込まれた依存を個別に確認します。WASIでは未対応APIがSC3002になることもテストに含めます。 第5章では、WASIと使えない機能に関係する入力、出力、エラーを分けて記録します。READMEが説明していない挙動は未確認として残し、成功した一回だけを互換性の根拠にはしません。
差分テストとキャッシュ
READMEはNodeとネイティブのstdout、stderr、終了コードを比較する差分テスト、AddressSanitizerと参照カウント監査を説明しています。これはプロジェクトの検証手順であり、自分のアプリの正しさの保証ではありません。キャッシュは内容アドレス方式で、SCRIPTC_NO_CACHE=1で無効化、SCRIPTC_CACHE_DIRで場所を変更できます。pnpm test:sandboxを使う場合は認証、ツールチェーン、Sandboxの版を記録します。
scriptcでは、同じhello.tsをNode、scriptc run、scriptc buildで実行し、stdout、stderr、終了コードを比較します。coverageの診断コード、.scriptc内のir、c、llvm、asm、obj、--dynamicで埋め込まれた依存を個別に確認します。WASIでは未対応APIがSC3002になることもテストに含めます。 第6章では、差分テストとキャッシュに関係する入力、出力、エラーを分けて記録します。READMEが説明していない挙動は未確認として残し、成功した一回だけを互換性の根拠にはしません。
編集部の結論
小さなCLIやサーバーをTypeScriptで書き、配布先にNode.jsを置きたくない開発者に向きます。実験的なため、npm依存やanyを含むコードが静的に通るとは考えないでください。まずscriptc coverage hello.tsで静的範囲と診断コードを確認し、build、実行、WASIの各成果物を対象OSで比較してから本番候補を決めます。
コミュニティノート