Slide 1

Slide 1 text

TypeScript Compiler は どのように未使⽤変数を検出しているのか? 2026/5/23 TSKaigi 2026 つねみ@tocomi

Slide 2

Slide 2 text

つねみ @tocomi 🏢テックタッチ株式会社 󰞵フロントエンドエンジニア 趣味 🥸 お笑い ⚾ 野球観戦(ヤクルトファン) 🃏 ポーカー 🎮 ゲーム 🏇 競⾺ ⾃⼰紹介

Slide 3

Slide 3 text

つねみ @tocomi 🏢テックタッチ株式会社 󰞵フロントエンドエンジニア 趣味 🥸 お笑い(M-1グランプリ2025 1回戦敗退) ⚾ 野球観戦(ヤクルトファン) 🃏 ポーカー 🎮 ゲーム 🏇 競⾺ ⾃⼰紹介

Slide 4

Slide 4 text

この発表では、未使⽤変数のチェックという観点から TSC (TypeScript Compiler) の内部動作の⼀部を⾒ていきます🚀 シンプルなサンプルコードを題材にして、TSC の内部でコードがどのような データ構造に変換されてチェックが⾏われるのか順に追っていきます👀 TypeScript v6.0.3 をベースに調査しています🔍 みなさんの知的好奇⼼を満たしたり、 TSC にディープダイブするきっかけになったら嬉しいです😌 今⽇の発表について

Slide 5

Slide 5 text

⽬次 🔖 1. 全体像 2. 各処理の詳細 3. まとめ

Slide 6

Slide 6 text

⽬次 🔖 1. 全体像 2. 各処理の詳細 3. まとめ

Slide 7

Slide 7 text

TypeScript Compiler の構成

Slide 8

Slide 8 text

TypeScript Compiler の構成 Code チェック対象のソースコード AST ソースコードの構⽂を⽊構造で表した中間表 現 Symbol Table 変数‧関数‧クラスなどの宣⾔や名前解決情 報を表すものの集合 Diagnostics 構⽂エラーや型エラーなどの情報 ここに未使⽤変数の警告が含まれる! Input / Output Parser Code を構⽂構造である AST に変換する Binder AST を⾛査し、名前と宣⾔を結びつけて Symbol Table を作る Checker AST と Symbol Table を使って型の整合性を 検査する Process ※Emit は省略してます

Slide 9

Slide 9 text

題材とするコード

Slide 10

Slide 10 text

⽬次 🔖 1. 全体像 2. 各処理の詳細 3. まとめ

Slide 11

Slide 11 text

Parser は、ソースコード を受け取り、AST に変換する Parser の役割

Slide 12

Slide 12 text

AST って? Abstract Syntax Tree(抽象構⽂⽊) の略 ソースコード内の関係性を、プログラムが扱いやすい⽊構造に変換したもの TypeScript に限らず、様々な⾔語やツールで利⽤される普遍的な構造 (ただし、変換後のノードなどはツール固有) ex) Babel, ESLint, Prettier, … AST に変換することで、コードを「⽂字列」ではなく「構造化データ」として扱 えるようになり、型チェックや未使⽤変数のチェックがやりやすくなる。 Parser の役割

Slide 13

Slide 13 text

Parser の役割 ソースコード AST

Slide 14

Slide 14 text

Binder は、AST を受け取り、Symbol Table を作る Binder の役割

Slide 15

Slide 15 text

Symbol? Symbol Table? Symbol とは、関数や変数、型の情報を持つオブジェクト。 名前をキーにして種類やどこで宣⾔されたかといった情報を持っている。 Symbol をスコープごとにまとめたものが Symbol Table。 使⽤されたかのフラグ(isReferenced)も Symbol が持つが、Binder の段階では フラグはすべて undefined の状態。 (JavaScript の組み込みオブジェクト Symbol とは全くの別物) Binder の役割

Slide 16

Slide 16 text

Binder の役割 SourceFile.locals (ファイル内のスコープ) └ 'addOne' -> Symbol(Function) FunctionDeclaration.locals (関数内のスコープ) ├ 'num' -> Symbol(FunctionScopedVariable) └ 'unused' -> Symbol(BlockScopedVariable) - スコープごとに Symbol Table が作られる - locals というフィールドに格納される - key は変数や関数、型の名前 AST Symbol Table

Slide 17

Slide 17 text

Checker は、AST と Symbol Table を受け取り、Diagnostics を作る Checker の役割

Slide 18

Slide 18 text

Diagnostics? 直訳すると「診断」。 TS Compiler がユーザーに返却する エラーや警告、情報メッセージを指す。 型エラーや未使⽤状態の警告がここに含まれている。 ex) 'unused' is declared but its value is never read. Checker の役割

Slide 19

Slide 19 text

1. return ⽂で num が使われてい る! 2. Symbol Table を⾒ると関数スコー プの引数に num が key の Symbol がある! 3. num の Symbol の isReferenced にフラグを⽴てる! Checker の役割 Checker の気持ち (実際は AST を⾒ている)

Slide 20

Slide 20 text

⼀⽅で、unused は宣⾔されているため Symbol Table には存在するが、使⽤さ れていないため isReferenced は undefined のまま。 そのため Diagnostics に未使⽤である 旨が登録される。 Checker の役割 Checker の気持ち (実際は AST を⾒ている)

Slide 21

Slide 21 text

Checker の役割 isReferenced の操作 src/compiler/utilities.ts line 11867 〜

Slide 22

Slide 22 text

Checker の役割 関数は呼び出されていれば使⽤されている? 関数の再帰呼び出しの場合、 呼び出されているからといって isReference フラグを⽴てるべきではない。 関数外から関数 fib()が呼び出されない限り、関数内の fib()が呼び出されることは ないため。

Slide 23

Slide 23 text

Checker の役割 Symbol Table の⾛査 src/compiler/checker.ts line 44611 〜

Slide 24

Slide 24 text

⽬次 🔖 1. 全体像 2. 各処理の詳細 3. まとめ

Slide 25

Slide 25 text

まとめ 未使⽤変数チェックという切り⼝で処理を追っていくことで、 TSC の裏側がちょっとだけ分かるようになった気がする💪 みなさんも、「ここってどういう原理で動いてるんだろう?」という疑問が あったら、調べてみると⾯⽩いかもしれません🙌

Slide 26

Slide 26 text

おわり