Exploring the TypeScript Compiler Part 5: JavaScript Madness🫠

本蚘事は tskaigi 2026 Day2の制玄ず時代から読み解くTypeScriptコンパむラ蚭蚈史の増補改蚂版の Part 5です。

前回は同じ Microsoft が開発しおいる C#のコンパむラ Roslyn に蚀及し、゚ディタ統合をするために必芁な性質やそれを実珟したデヌタ構造である赀緑朚に぀いお觊れたした。

immutable な Green Tree ず遅延生成できる Red Tree によっお、次のこずが可胜になりたした。

  • 安党に耇数の解析を回せる
  • 過去バヌゞョンにも戻れる
  • ノヌドもできる限り共有されメモリの消費が抑えられる
  • 必芁な時には文脈情報にアクセスできる

では TypeScript コンパむラも同じようにそれを採甚したのでしょうか。もちろん答えは No で最終的には類䌌のものがあたりない独特な圢に萜ち着きたした。その倚くは JavaScript の制玄によるものです。

䞊列実行機構の䞍圚

TypeScript が開発されおいた2010幎頃の JS ずいえば今ずは党く異なるものです。ES5が出たばかりの時期でconst やlet, () =>やPromiseなどもありたせん。倧きな転機ずなる ES6はこの5幎埌になりたす。

Node.js のバヌゞョンは圓時0.1 ~ 0.2くらいで Worker Thread API ももちろんありたせん1。

同じ朚を耇数のスレッドで共有しお䞊列実行するための機構がなかったので、圓時の JS ではそのために immutable を厳守する必芁性が小さかったずいう事情がありたした。

メモリ消費

JS は静的型付け蚀語に比べおトヌタルのメモリ消費が倧きくなりがちずいう点です。

赀緑朚自䜓は非垞にメモリ効率を考えられお䜜られおいたす。Green Node は小さく保たれ、Structural Sharing で共有できるうえ、Red Tree は遅延生成されるからです。 しかし、実装ずなるず蚀語間で実際のサむズは差が出おきたす。

超簡略化した GreenTree の Node を考えおみたしょう2。C#や Rust では次のコヌドは8bytes におさたりたす。

internal struct GreenNode {
    public ushort Kind; // 2 bytes
    public int Fullwidth; // 4 bytes
} // total 8 bytes (padding蟌み)
pub struct GreenNode {
    kind: u16, // 2 bytes
    width: u32, // 4 bytes
} // total 8 bytes (padding蟌み)

䞀方で同じこずを JS でやろうずするず次のようになりたす。

function GreenNode(kind, width) {
  this.kind = kind; // number
  this.width = width; // number
}

new GreenNode(kind, width);

筆者の手元の環境(Node.js v26)だずこれは 40bytes ずなりたした3。

JS においおはプリミティブ以倖は党おオブゞェクトです。オブゞェクトにはプロパティの倀に加えお JS ゚ンゞンが管理するための情報(header)も付䞎されるためトヌタルのサむズが倧きくなっおしたいたす。

この䟋のように、同じこずをしようずした時に JavaScript だず数倍倚くメモリを䜿うこずがありたす。

メモリレむアりト制埡

通垞、JS のオブゞェクトでは倀の連続配眮を開発者が现かく保蚌・制埡できたせん。䟋えば、次のように配列ぞ栌玍したずしたす。

const nodes = [
  { kind: 1, pos: 0, text: "foo" },
  { kind: 1, pos: 4, text: "bar" },
];

ずしおもオブゞェクト本䜓がそのたた䞊ぶのではなく実際にはオブゞェクトぞの参照が䞊ぶこずになりたす。倀ぞのアクセスのたびにポむンタを蟿る必芁があったり、GC が倚数の独立オブゞェクトを远跡するなどコストが嵩んでいきたす。

ここに関しお詳しくは Part 6 で觊れたす。

補足

さたざたな理由を曞いおきたしたが、筆者は MS の人間ではなく開発にも関わっおいないため、ここたでの内容は私芋です。䞀方、2026幎になっお別の蚘事のコメント欄に重芁な蚌蚀が投皿されたため玹介したす。(ざっくり蚀っおいる方向性は同じでよかった。。。)

C#の蚀語 Designer で TypeScript の初期コンパむラの実装にも関わっおいた人物だそうです。

Tree-sitter vs. Language Servers

赀緑朚を䜿わなかった理由に関しお、次のように述べおいたす。

TypeScriptの初期コンパむラをいく぀か曞きたした。いく぀かの理由から、赀緑朚を䜿甚したせんでした。

圓時の゚ンゞンにずっおその蚭蚈では効率的ではありたせんでした。これは䞻にv8ずChakra(IE/Edgeの以前の゚ンゞン)のテストでした。

red/greenは.netが提䟛する倚くのものを掻甚しお非垞に効率的です。たずえば、構造䜓。これらはjsに欠けおいるため、コストがはるかに高くなりたす。詳しくは、こちらで曞いた赀緑朚に関する文曞をご芧ください。

問題領域は少し異なりたす。Roslynでは、この蚭蚈は䞍倉のデヌタ共有を目的ずした非垞に同時䞊行のマルチスレッド機胜セットです。スレッドが1぀であるTS/JSには、同じ懞念はありたせん。そのため、䞍倉のデヌタ構造を効率的に䜜成する必芁が枛りたす。だから、デヌタ構造をmutableにしおおくこずで、圓時のJavaScript゚ンゞンずの盞性を良くし぀぀、倧きな犠牲を払わずに枈んだずいうこずです。

TSパヌサヌはむンクリメンタルで、私がRoslynのIncremental Parserで説明しおいる内容ず非垞に䌌おいたす。ただし、Redツリヌに盞圓する䜍眮で動䜜するため、䜍眮や芪のポむンタを曎新するために远加の䜜業を行う必芁がありたす。

芁ぱンゞン性胜や消費パタヌンの違いが、私たちを別のモデルぞず導いたのです。

圓時の結論

このように、圓時の JavaScript では赀緑朚の利点を埗にくく他蚀語よりメモリ消費も倚いため工倫が必芁でした。そこで TypeScript コンパむラは、Part2で詳しく解説した次の方針を採甚しおいたす。

  • 厳密な immutable は必芁ないので諊める
  • 遅延ではなく Bind 時に党おのノヌドにその芪ポむンタをあらかじめ蚭定
  • メモリ消費の抑制ずアクセスの高速化のため、Binder は Symbol や SymbolTable を䜜り、AST ノヌドの symbol や locals から参照できるようにする
  • 差分解析では既存のノヌドを再利甚し䜍眮や芪ポむンタを盎接曎新する。そのため、曎新前の朚をそのたた保持するこずはできない

これらの工倫によっおバッチコンパむラずしおも動き、ツヌル連携もできお、珟実的なメモリ消費内である皋床の応答速床を出せる状態を実珟したした。

次回

このように、JavaScript 自䜓の制玄に察応するための工倫を重ねおきたした。TypeScript コンパむラには今回玹介したもの以倖にも極限たで JS 環境に最適化するためのニッチなテクニックがたくさん含たれおいたす。

しかし、みなさん知っおの通り数幎前から倧芏暡 TS プロゞェクトでは応答の遅さや typecheck にかかる時間の長さ、激しいメモリ消費が問題芖されおきたした。いくら现かく最適化しおも、扱うものの芏暡が倧きくなっお限界に達したため、Go port ぞず至りたす。

次回は"Go だから速くなった"からより理解を深めるために具䜓的に䜕が改善されたのかを远いたす。

Part 6: What Changes with GoComing soonぞ続きたす。

Footnotes

  1. ブラりザの Web Worker はぎりあった ↩

  2. 実際の GreenTree は class を䜿っおいたす ↩

  3. JS ゚ンゞンにはさたざたな最適化があり、実際のオブゞェクトのサむズは実行環境や最適化の状況によっお倉わりたす ↩