Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
TSKaigiSendai2026.pdf
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Saji
November 01, 2026
86
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TSKaigiSendai2026.pdf
TSKaigi Sendai 2026
-
https://sendai.tskaigi.org/talks/14
X
-
https://twitter.com/sajikix
Saji
November 01, 2026
More Decks by Saji
See All by Saji
Intlのここ数年とこれから
sajikix
0
57
本当はややこしい日時のFormatPattern
sajikix
0
460
tpac_study (2026)
sajikix
0
390
業務に残された「良くない型」で考える「TypeScriptの難しさ」
sajikix
4
9.6k
It’s “Time” to use Temporal
sajikix
3
840
ユーザーが作成したコードをブラウザ上で安全に実行できる Plugin システムへのアプローチ
sajikix
1
910
Branded Typesで日時の複雑さと戦う
sajikix
4
1.3k
推しProposalと広がる夢~Intl.MessageFormatとDomLocalization~
sajikix
2
880
自作JSエンジンに推しプロポーザルを実装したい!
sajikix
1
400
Featured
See All Featured
Git: the NoSQL Database
bkeepers
PRO
433
67k
Raft: Consensus for Rubyists
vanstee
143
7.8k
Into the Great Unknown - MozCon
thekraken
41
2.8k
RailsConf 2023
tenderlove
30
1.6k
WENDY [Excerpt]
tessaabrams
14
40k
Exploring anti-patterns in Rails
aemeredith
4
550
The browser strikes back
jonoalderson
0
1.9k
Marketing to machines
jonoalderson
1
5.9k
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
880
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
510
Designing Powerful Visuals for Engaging Learning
tmiket
1
620
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
730
Transcript
静的型チェックの先の恩恵を考える 〜TypeScriptはビルド最適化の夢を見るか〜 Ryusei Sajiki / @sajikix
𝕏 Saji / Ryusei Sajiki Frontend Developer at Cybozu, inc.
@sajikix
原則: TS の型はビルドにも 実行にも影響しない
原則:型は付随情報 実行時やbuild時にTSの型情報は消える • tsc や esbuild は型注釈を消すだけ。 • Node も型注釈を消して
TS を実行する(type stripping) • 型エラーがあっても、tsc は同じ JS を出力する • JSON.parse(s) as Foo の Foo が間違っていても、実行結果は変わらない
…はずなんですが
型でビルド結果を変えるツールがある イメージ 型なし最適化 元コード class a { class Cart {
型あり最適化 class a { constructor() { constructor() { items: string[] = []; this.items = []; this.h = []; count = 0; this.count = 0; this.g = 0; add(item: string) { this.items.push(item); } } add(c) { add(c) { this.count++; } } this.items.push(c); this.h.push(c); this.count++; this.g++; } } } }
アジェンダ 型を情報を利用してビルド最適化を行うツール群を新旧3つ紹介する 1. Closure Compiler: 型を全面的に信じるトランスパイル 2. scriptc: 証明された型は信じ、主張された型は検証するコンパイル 3.
Bun —aot : 型を予測として使い動作は変えないコンパイル その上で型をチェック以外のビルド最適に使う未来を考える
遡ること2009年 🕰
1. GoogleClosureCompiler
Closure Compiler Google Closure Compiler Gmail や Google マップのような大規模な JavaScript
アプリケーションを開 発するために、Google が作った最適化コンパイラ。2009年公開 • 2009年当時そこまで一般的でなかった モジュール解決 / JSDoc の注釈での 型 / 最適化を含むビルドを独自の形でサポートする意欲的なツールだった • Closure Libraryなどと一緒に公開され利用されてた(※) • 豆知識 : JSのSourceMapの仕様はClosure Compiler発 / 今でもReactの buildの中で使われてたりする ※ClosureLibraryの方は現在EOLになっている😭(弊社は一部まだ使ってる)
Closure Compiler Google Closure Compiler のビルド最適化 3段階の最適化レベルを持ってる • WHITESPACE̲ONLY :
空白除去のみ • SIMPLE : ローカル変数のリネームなど、一般的な mini er 相当 • ADVANCED : プログラム全体を解析し、プロパティ名のリネーム、関数のイ ンライン化、到達しないコードの削除まで fi → 今回の話は ADVANCEDの時+型をちゃんと書いた場合の話
Closure Compiler Google Closure Compiler での型 class Cart { constructor()
{ /** @type {!Array<string>} */ this.items = []; /** @type {number} */ this.count = 0; } /** @param {string} item */ add(item) { this.items.push(item); this.count++; } } 特徴 • JSDoc で書く • Closure 自身の型チェッカーが検査 • TSと色々違う • オブジェクトの型は既定でnull許容 • anyに似た ? 型 • /** @type {!X} */ (式) でキャスト
Closure Compiler 型情報を使ってサイズを削減できる! 条件 サイズ SIMPLE 712,558 - ADVANCED (型を使わない)
38,469 -94.6% ADVANCED (型を使う) 29,236 対SIMPLE 対型なし -95.9% ツール Raw Zip - Vite 9,249 3,442 - esbuild 9,273 3,485 -24.0% Closure ADVANCED 7,251 3,016 オプションによるサイズの違い 他ツールとの比較 ADVANCEDモードで型情報を使うとサイズをさらに削れる • (ADVANCEDモード単体も十分優秀だけど…)
Closure Compiler 型情報でなぜサイズを削れるのか? 型で同じ名前のプロパティを別のものとして区別できることが大きい 同じ名前のプロパティ同士の区別が付くと… • 呼ばれていないメソッドの削除ができる • DOM などと同じ名前のプロパティを短縮できる
• 関係のない型どうしは同じ短い名前を使い回して短縮できる • etc..
Closure Compiler 型を使った最適化を使える条件 そもそもADVANCEDモードを使うには条件がある • コードが基本的に閉じている(externsで宣言したもの以外外から触らない) • quotedアクセス・Object.keys・JSONを経由した名前を扱わない etc.. 型による最適化を利用する場合の制限もある
• 型注釈が実際の値と一致している前提(=型を全面的に信じる) • nominal な型でしか最適化されない(構造的な型は最適化の対象外)
Closure Compiler Q.型で嘘ついたらどうなるの?
Closure Compiler A. 実行時に壊れる😭(ことが多い)
Closure Compiler 条件を破ると警告なしで壊れる class Cart { constructor() { /** @type
{number} */ this.count = 0; } } const saved = /** @type {!Cart} */ JSON.parse('{"count": 41}'); console.log(saved.count); savedをCartだと信じる → Cartと同し形でプロパティを短縮できるはず fi → 実際のJSONにそんなプロパティはない!🤯 (unde nedで勝手に進む)
Closure Compiler ClosureCompiler まとめ • 実はTSが生まれる前から型情報によるチェックとビルド最適化は行われてる • 宣言でされた型情報を利用することでコード削減が可能 • 型の恩恵による部分は若干少なめだが確かにある
• ただしClosureCompilerにおける型を利用した最適化は「書いた型を無条件 で信じることができる」という強い仮定の上に行われる
back to 2026 🙌
2. scriptc
scriptc scriptcとは Vercelが開発している、TS(JS)をNode なしで動くネイティブの実行ファイル にコンパイルするコンパイラ。 • 2026-07に公開されて現在はまだ0系 • TSの型情報をコンパイルの最適化に利用する
scriptc scriptcの最適化戦略 関数ごとに、2種類のどちらかでコンパイルするか決める • static tier : 型から決めた表現でコンパイル (←こっちに入りたい!) •
dynamic tier: 実行時に値の型を調べるネイティブコードにコンパイル static tierに入るためには? 1. 関数ごとに型のない値(dyn)を見つける 2. 1で見つけた型のない値を操作していないと言える → ちゃんと型書いておくのが大事!
scriptc static tierでどのくらい速く・小さくなるのか 同じ処理で型付きの TS と、型注釈だけを取り除いた JS をビルドしてみた • 対照としてNodeでの実行も入れてる
速度 型付き 型なし 型なし / Node(型 型付き なし JS) 数値計算 41 ms 1.63 s 40 倍 72 ms 数値計算 127 KB 487 KB 3.8 倍 Object操作 138 ms 870 ms 6.3 倍 370 ms Object操作 215 KB 616 KB 2.9 倍 型分岐操作 87 ms 9.4 倍 123 ms 型分岐操作 146 KB 580 KB 4.0 倍 818 ms サイズ 型付き 型なし 型なし / 型付き 条件 : Apple M4 Pro、macOS 26.6.2、scriptc 0.4.6Node v26.12.1
scriptc 型でなぜ速く・小さくなるのか 型情報による最適化で速度に聞いていそうなのは以下 • オブジェクトを固定レイアウトで持てる : メモリの配置や読み込みで有利 • ネイティブ側の近い型に変換できる :
number → double で持つ等 • union の分岐で実行時に型を調べる処理を省ける • ジェネリクスを型引数ごとに別のコードにするといったこともできる サイズに関しては「実行時の型判定コード」がいらなくなるのが大きい
scriptc 型をどこまで信じるのか • 型チェッカーが推論した型(narrowing を含む) • 信じてメモリレイアウトの固定や分岐の省略に使う • as・!(narrowing)・.d.ts・JSON.parse などの結果
• あくまで主張とみなし、値が型付きの側に入るところで検査する • any・型のないコード • dynamic tier で、実行時に型を調べる
scriptc Q.型で嘘ついたらどうなるの?
scriptc A. 実行時に型検査エラー🙅
scriptc 型で嘘をつくとどうなるのか? interface Cart { count: number; } const saved
= JSON.parse(process.argv[2]) as Cart; // ← error console.log(saved.count); 実行時エラーとして止まりどのパスで何が違うかエラーに出る • > TypeError: expected number at $.count, got string • アサーションが間違ってた際やany型を代入しようとした時も同様
scriptc scriptc まとめ • scriptc は、型チェッカーが証明した型を信じ、主張された型は実行時に検査 する形で最適化 • 実は10/20 に型と合わない値でも実行を続ける変更(#1561)が入り、同じ
日に revert された(#1601)。 • 理由: "scriptc's premise is that types don't lie” • 型が正しく書かれている場合は実行速度でもサイズでも強い最適化が入る • 一方 as などを使って「嘘をついている」とNode で動くプログラムが ̀TypeError̀ で止まることがある
3. bun の --aot
bun ̶aot Bunのbuildコマンドにおける --aot オプション Build時にTS/JS をビルド時に機械語へコンパイルし、実行ファイルを作るオプ ション、--aotが追加された • bun
build --compile --aot のように実行する • --compile オプション単体だとJSファイルと実行ランタイムをまとめたフ ァイルになる • Scriptc同様にTSで書かれた型を使ってコンパイルの最適化を行う ※かなり実験的な機能なので発表時:2026/11/01以降大きく変わる可能性があります
bun ̶aot Bunの --aot 時ののコンパイル TSをコンパイルする場合、関数ごとに次の3つをまとめて生成する • 入口の検査: 渡された値が型どおりかを調べる •
型最適化版: 型どおりの値が来たときに使う • 汎用版: 型どおりでない値が来たときに使う 実行時にテストをし、値が型通りでなかったら汎用版にfallback • 型は外部からくる予測の型とフロー解析で確定した型に分けて管理
bun ̶aot 型による最適化で速く・小さくなるのか…? 処理 命令数(型あり / 型なし) 一般的なイディオム(中央値) 1.00 小さなオブジェクトの
JSON.parse 0.30 ループ内の分割代入 0.18 パッケージ 1 回の描画 0.96 結果 • 速度: JSON.parseのような特徴的な処理以外はそこまで速くならない • サイズ: むしろ型ありのほうが約 1 割大きくなる
bun ̶aot 型でなぜそこまで速く・小さくならないのか メモリのレイアウト固定の大部分は型ではなくフロー解析で決まる • 型が効くのは、解析で追えない値がメイン • 性能比較で差が出た JSON.parse と分割代入がこれにあたる
• 型は予測として扱うだけで入口の検査が必ず残る サイズに関してはむしろ不利 • 予測した型を使う関数は、本体に加えて入口のテストと汎用版を持つ
bun ̶aot Q.型で嘘ついたらどうなるの?
bun ̶aot A.汎用版にfallbackするだけ😊
bun ̶aot 型で嘘をつくとどうなるのか? 遅くなるだけで、結果は ̀bun ruǹ と同じになるようfallback interface Cart {
count: number; } const saved = JSON.parse(process.argv[2]) as Cart; console.log(saved.count); // OK 型の不一致を記録するオプションにすると型違反が起きてることはわかる • > expected Cart, got untyped object; continued
bun ̶aot Bunの--aot まとめ • Bun --aot は、型を予測として使い、外れたら汎用版で動くことで、実行結 果を型に依存させない •
その代わりに型による最適化は境界部分に集まり、全体としては小さい。 • ※この辺りの設計は直近2週間で入れ替わってるので不安定 • 10/09 の投稿では as が値を変換し、JSON.parse の結果が型と合わなけ れば TypeError(scriptc に近い設計)だった • 10/22 にこれを「throw・変換しない」設計に変わった。
3つを比べてみよう
これまでの3つを並べる 型で嘘をつくと 速度(型あり / 型なし) サイズ(型あり / 型なし) Closure 警告なしで壊れる
基本同じ Closure 向けコードで -24%、普通の書き方で -7% scriptc 止まる(TypeError) 8〜35 倍速い 3〜4 分の 1 Bun --aot 遅くなるだけで、結果は同じ ほとんど同じ~少しだけ速い 約 1 割大きい tsc 何も起きない 同じ 同じ
型を信じるメリデメと得られるもの 傾向 : 型を信じるほど得られるものもリスクも大きい + 効くのはネイティブ メリット Native Transpile scriptc
(速い&小さい) Closure Compiler (多少小さい) Bun ̶aot (少しだけ速い) tsc (変わらない) リスク 特になし 少しサイズ増 実行時エラー 警告なしで壊れる
これからどうなってくんだろう
そもそも型を信じるのは強い仮定である TypeScript の型システムは、健全(sound)であることを目標にしていない • これを無理やり「信じる」と言うのはかなり強い仮定になる • TSの型を信じるコンパイラは「型が実態と違うことがある」という事実をど こかで引き受けなければならない 信じ切るかどうか(=嘘だったらどうするか)はツールごとに揺れている •
奇しくもscriptc と bun はお互いに逆の思想を入れようとしてやめている
TSのネイティブコンパイルの潮流 TS/JS をネイティブや Wasm にコンパイルするツールが直近いくつか出ている • Static Hermes(Meta)の typed mode
• 型が嘘にならないよう言語の意味側を変える(配列の範囲外アクセスは例外) • 使えるTSの記法は限られる • Por or ff • ClosureCompiler同様型を愚直に信じるタイプの最適化をおこなう
これから : それでも型を信じ切れるか トランスパイル(to JS)に関して言うとリスクの割にメリットが薄め(だと思う) • 他のビルド最適化手法と比べると相対的に効果が弱い ネイティブにコンパイルするツールに関してはトレードオフとして採用しそう • いろんな制約と最適化のバリエーションが増えていくのではないか
やっぱり型で嘘はなるべくつかない方がいい • どこかで将来的な最適化の芽を摘んでる可能性がある
2027年はTS(の一部)が 型チェックのため「だけ」じゃなくなる年 …かもしれない 夢見たい!
ご清聴ありがとうございました