Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
型情報を手繰り寄せる技術~TypeScript Compiler APIによる型解析実践~
Search
jiko21
November 23, 2025
0
19
型情報を手繰り寄せる技術~TypeScript Compiler APIによる型解析実践~
TSKaigi Hokurikuの資料です
jiko21
November 23, 2025
Tweet
Share
More Decks by jiko21
See All by jiko21
Creating a Next.js-style Framework with Bun and Hono
jiko21
0
150
Array Grouping will soon be arriving at TypeScript
jiko21
0
130
Copying Array Methods arrived at TypeScript
jiko21
1
690
SSRで動的に OGP画像を生成したい! 〜Cloudflare Workersから@vercel/og移行編〜
jiko21
0
140
node:test will replace Jest?
jiko21
0
97
どこでも動かすために… TypeScriptでライブラリ開発の すゝめ
jiko21
2
390
NestJS a progressive web framework
jiko21
3
2.2k
レガシーなフロントエンドをリプレイスする
jiko21
5
1.6k
Deep Dive Into Vue Composition API
jiko21
0
3.2k
Featured
See All Featured
What's in a price? How to price your products and services
michaelherold
246
12k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.3k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
231
22k
How to train your dragon (web standard)
notwaldorf
97
6.4k
4 Signs Your Business is Dying
shpigford
186
22k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.8k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.1k
Facilitating Awesome Meetings
lara
57
6.7k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.8k
Making the Leap to Tech Lead
cromwellryan
135
9.6k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.2k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
196
69k
Transcript
型情報を手繰り寄せる技術 ~TypeScript Compiler APIによる型解析実践~ TSKaigi Hokuriku 小島大基 (@jiko21) / エムスリー株式会社
自己紹介 • 名前: 小島大基(こじまだいき) / @jiko21 • 所属: エムスリー株式会社 •
北陸の思い出 • 2年前、大阪から金沢までサンダーバードを使って観光旅行に行きました • 金箔入りソフトクリームがおすすめ
突然ですが…
型から何かを生成したくないですか?
型から生成できるとうれしいもの • APIのSchema • IF定義(open-api)からの生成はあるが実装からIFを作りたいetc • テスト用ダミーデータの生成 • いつも自前で実装しているが型からfaker等利用して生成できると楽 •
その他いっぱい…
ワイ「型からHTML生成したい!」
型からHTMLを生成したいモチベーション • HTMLのセマンティクスやルールに沿ったHTMLだけを書ける状態にしたい • NGパターン1 inline要素の中に block要素は置けない
型からHTMLを生成したいモチベーション • HTMLのセマンティクスやルールに沿ったHTMLだけを書ける状態にしたい • NGパターン2 ブロック要素があると pタグは閉じられる ブロック要素があると pタグは閉じられる
こういうものを作りました!
html-typeについて • TypeScriptの型からHTMLを生成するライブラリ
html-typeについて • Pの中でDIVを利用するなど、HTMLのセマンティクスに違反する場合 型エラーとなる
html-typeのやっていること • 型の提供 • 各HTMLのタグに対応する型を提供 • Html<T>, Body<T>, Div<T>, P<T>
• TypeScript Compiler APIによる型解析
html-typeのやっていること • 型の提供 • 各HTMLのタグに対応する型を提供 • Html<T>, Body<T>, Div<T>, P<T>
• TypeScript Compiler APIによる型解析
TypeScript Compiler API
TypeScript Compiler APIって知ってます? • TypeScriptを解析するためのAPI • 型情報やコメント等をAST(抽象構文木)で取得できたり、型生成したりできる • 実際に使われているプロダクト •
ESLint • openapi-typescript • etc • TypeScript Goの登場でjsから直接触ることはできなくなる可能性があるので注意…
• TypeScriptの型をASTに変換する TypeScript Compiler APIでできること
html-typeのやっていること • 型の提供 • 各HTMLのタグに対応する型を提供 • Html<T>, Body<T>, Div<T>, P<T>
• TypeScript Compiler APIによる型解析
TypeScript Compiler APIを使っていく
よくみるサンプルコード そもそもこれって何?
よくみるサンプルコード
͍͢͝Ͱ͔͍ΦϒδΣΫτ͕දࣔ͞ΕΔʜ
オブジェクトがよくわからな い…
まずは外部ツールでASTを見てみる • TypeScript AST Viewer (https://ts-ast-viewer.com/) を使えばどうい うASTに変換されるかわかる • 実際に型を解析する前にこのサイトで解析したい型がどういうASTかを
見てみるとよい
まずは外部ツールでASTを見てみる
ちなみに… • ts.Nodeにはkindというフィールドがあり、ここにASTの種類を表す 値(数字)がありますが300種類以上あります→ • あくまで実装時のデバッグに使う、くらいの気持ちで いるほうがいいかも
ちなみに…
それぞれのkindにあわせてparse • 先程のnode.kindを使って解析してみると…
None
Kindだけでは(型的に)絞り込めない • kindだけではASTの種別を型的に識別できない • (残念ながら)Disciminated Unionではない • TypeAliasDeclaration型の継承関係を見てみるとこんなに複雑 TypeAliasDeclaration DeclarationState
LocalsContainer JSDocContainer NamedDeclaration Statement Declaration Node
isXXXを使う • isXXXを使うとに単true/falseを返すだけでなく型ガードにより 推論してくれる • 今回だとisTypeAliasDeclaration
isXXXを使う • isXXXを使うとに単true/falseを返すだけでなく型ガードにより 推論してくれる • 今回だとisTypeAliasDeclaration
実際にHTML型をparseしていく
軽くhtml-typeの型について • <html>、<body>、<div>、<p>について型として定義されている • HTMLとして子要素に持てるもの(HTMLNodeとする)は • 文字列(Text) • HTMLNode •
HTMLNodeあるいはTextを含むリスト • 例えば<html>タグは右のように定義されている
None
• 以下のようなシンプルなASTをパースしていく まずはシンプルなケースでパースしていく
• SourceFile自体がファイルのrootに位置するのでそこから深さ優先で 再帰処理していく 頭にあるSourceFileを識別 SourceFile
• TypeAliasにヒットすると次は型の内部を見ていく TypeAliasを識別 TypeAlias
• 内部構造見てみるとIdentifierとTypeReferenceを持つ TypeAliasを識別 TypeReference Identifier
• node.type.typneNameがIdentifier TypeAliasを識別 TypeReference Identifier
• getTypeAtLocation、typeToTypeNode を使ってちゃんとTypeReferenceを 解析していく TypeReferenceを解析していく
むずかしい
前提知識 • よく出てくる登場人物はこれ • Type: 型システムが扱う型そのもの(ASTではない) • Node: AST Node全般
• TypeNode: 型に関するNode(Nodeを継承している)
前提知識 • NodeからTypeの情報が欲しいとき • TypeからそのNodeの情報が欲しいとき
• getTypeAtLocation、typeToTypeNode を使ってちゃんとTypeReferenceを 解析していく • typeToTypeNodeの第三引数が かなり大事!(一旦undefinedで) • TypeReferenceだと中の型情報が 取り出せない!
TypeReferenceを解析していく
• node.membersでそれぞれの構成要素を取得できる ひたすらTypeLiteralNodeを解析していく Identifier PropertySignature
None
ひたすらTypeLiteralNodeを解析していく • node.membersでそれぞれの構成要素を取得できる • Indentifier: 型名が取得できる • PropertySignature: 今回の場合は Genericsの部分
Identifier PropertySignature
PropertySignatureを解析する前に…
軽くhtml-typeの型について(再掲) • <html>、<body>、<div>、<p>について型として定義されている • HTMLとして子要素に持てるもの(HTMLNodeとする)は • 文字列(Text) • HTMLNode •
HTMLNodeあるいはTextを含むリスト • 例えば<html>タグは右のように定義されている
PropertySignatureをパース • PropertySignatureは3種類ありうる • 文字列リテラル: StringLiteral • タプル(配列): TupleTypeNode •
Typeリテラル: TypeLiteralNode
• PropertySignatureは3種類ありうる • 文字列リテラル: StringLiteral • タプル(配列): TupleTypeNode • Typeリテラル:
TypeLiteralNode PropertySignatureをパース
• 文字列リテラル: StringLiteral • そのまま文字列を取り出す PropertySignatureをパース StringLiteral
• タプル(配列): TupleTypeNode • タプル内要素を再度解析する PropertySignatureをパース TupleTypeNode
• Typeリテラル: TypeLiteralNode • 要素が1つだけなのでその要素を再度解析 PropertySignatureをパース TypeLiteralNode
• PropertySignatureは3種類ありうる • 文字列リテラル: StringLiteral • そのまま文字列を取り出す • タプル(配列): TupleTypeNode
• タプル内要素を再度解析する • Typeリテラル: TypeLiteralNode • 要素が1つだけなのでその要素を再度解析 PropertySignatureをパース StringLiteral TupleTypeNode TypeLiteralNode
実際のASTの構造
生成ができた
より複雑なものをparseしてみる • もっと複雑なものをparseしてみると…
• ここは本来、TypeLiteral>TypeLiteral>StringLiteralとはいるはず… 何が起こっているかを見てみる
何が起こっているかを見てみる
• ここは本来、TypeLiteral>TypeLiteral>StringLiteralとはいるはず… 何が起こっているかを見てみる どうやら省略されてそう…
型解析は不可能
と言う前に…
Configでいじれるところを見る • 今までのコードの中で、何かしらConfigを 入れられそうなのは右の5つ
None
None
None
None
None
TypeToTypeNodeを見てみると… • 今までundefinedで誤魔化してましたが第三引数が大事 • NodeBuildingFlagsにいろいろなフラグがある
None
NodeBuildingFlagsを使う • 今回はTruncate(…)を防ぎたいのでNoTruncateを使う • シフト演算でそれぞれのフラグ定義されているので、 複数のフラグも指定可能!
ちゃんとTruncationが治った!
ここだけの話 • Truncateが出たときにClaude Codeに相談したところ、 すごい力技でTruncateした部分を解消しようとしてました… • ↑まだTypeScript CompilerのことはClaudeもわからない? あるいはそれくらい情報が少ない?
まとめ • まずはAST ViewerでASTを見てみるべし • Compiler Optionは要注意 • TypeScript自体のコードを見るべし •
GitHubじゃなくて手元にClone!(GitHubだと多分みれない…)
良い型ライフを!