Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Real World Type Puzzle and Code Generation
Search
Yuku Kotani
May 11, 2024
Technology
4
900
Real World Type Puzzle and Code Generation
TSKaigi 2024
https://tskaigi.org/
Yuku Kotani
May 11, 2024
Tweet
Share
More Decks by Yuku Kotani
See All by Yuku Kotani
Expoによるアプリ開発の現在地とReact Server Componentsが切り開く未来
yukukotani
3
380
React 19でお手軽にCSS-in-JSを自作する
yukukotani
5
700
僕が思い描くTypeScriptの未来を勝手に先取りする
yukukotani
11
3.1k
Web技術を駆使してユーザーの画面を「録画」する
yukukotani
14
7.4k
Capacitor製のWebViewアプリからReact Native製のハイブリッドアプリへ
yukukotani
5
1.5k
Kuma UI が提唱する Hybrid Approach CSS-in-JS の仕組み
yukukotani
2
540
GraphQLスキーマ設計の勘所
yukukotani
42
18k
既存Webサービスのモバイルアプリ版を 1週間でリリースし、進化させてきた話
yukukotani
0
760
先を見据えたMVPのフロントエンド開発
yukukotani
0
310
Other Decks in Technology
See All in Technology
初めてのPostgreSQLメジャーバージョンアップ
kkato1
0
410
ソフトウェア開発におけるインターフェイスという考え方 / PHPerKaigi 2025
k1low
9
3.9k
コード品質向上で得られる効果と実践的取り組み
ham0215
2
200
Restarting_SRE_Road_to_SRENext_.pdf
_awache
0
160
年末調整プロダクトの内部品質改善活動について
kaomi_wombat
0
210
IAMのマニアックな話 2025 ~40分バージョン ~
nrinetcom
PRO
8
920
サーバシステムを無理なくコンテナ移行する際に伝えたい4つのポイント/Container_Happy_Migration_Method
ozawa
1
100
Javaの新しめの機能を知ったかぶれるようになる話 #kanjava
irof
3
4.9k
日本MySQLユーザ会ができるまで / making MyNA
tmtms
1
360
移行できそうでやりきれなかった 10年超えのシステムを葬るための戦略
ryu955
2
400
Dapr For Java Developers SouJava 25
salaboy
1
130
大規模アジャイル開発のリアル!コミュニケーション×進捗管理×高品質
findy_eventslides
0
520
Featured
See All Featured
How to Ace a Technical Interview
jacobian
276
23k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
30
2.3k
Writing Fast Ruby
sferik
628
61k
Making Projects Easy
brettharned
116
6.1k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
60k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
7
620
Side Projects
sachag
452
42k
Measuring & Analyzing Core Web Vitals
bluesmoon
6
320
Building a Modern Day E-commerce SEO Strategy
aleyda
39
7.2k
Faster Mobile Websites
deanohume
306
31k
GraphQLの誤解/rethinking-graphql
sonatard
70
10k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.2k
Transcript
Real World and Type Puzzle Code Generation @yukukotani 2024/05/11 -
TSKaigi 2024
小谷 優空 - @yukukotani ・Software Engineer @ Ubie, Inc. (2019/05~)
・Lead Architect ・Maintainer of Kuma UI ・Student @ Univ. Tsukuba (2019/04~) ・情報科学類 自己紹介
趣旨 型安全なコードを吐くコードジェネレータを作る野暮用があった(あるある) → 型安全 + コードジェネレータ = → 観察してエッセンスを抽出しよう! Prisma
観察するスキーマ このスキーマから生成されるコードを観察する User と Post がリレーションを持つ簡単なやつ
型パズルでselectした値に型をつける
None
None
簡略化した実装を観察する これが動くPrismaClient型(findFirst関数)の実装 スキーマに即した型がつく TS Playground
PrismaClient型 実際はクラスとして実装されているが、ここではシンプルなオブジェクト型に
入力の型を得る Type Argument Inferenceによって 型引数Tが推論される
入力の型を得る 型引数の制約は入力時の補完・エラー用。 GetSelectIncludeResultの導出には 条件型を使うので無関係
入力の型を得る 型引数の制約は入力時の補完・エラー用。 GetSelectIncludeResultの導出には 条件型を使うので無関係
出力の型を導出する 続いて出力の型を組成する要素を見ていく
$XxxPayload型 スキーマのモデルと対応して生成される カラムの型や他モデルとのリレーションを表現 → select結果の型を決定するための マスタとして機能 schema.prisma 生成される型
出力の型を導出する 第2型引数には入力の型をそのまま渡す
出力の型を導出する いよいよ出力の型そのものを見ていく
GetSelectIncludeResult<P, A> 事前生成のPayload型(P)とユーザーが渡す引数(A)から、select結果の型を導出
GetSelectIncludeResult<P, A> 条件型 `T extends { foo: infer S }
? S : never`パターンで、selectした中身を取る
GetSelectIncludeResult<P, A> Mapped Types で型を組み立てる
GetSelectIncludeResult<P, A> selectしたキーを Mapped Types のキーとする
GetSelectIncludeResult<P, A> キーに対応する値がfalse等の場合はneverにキャストして除外 Mapped Typesのキーを neverにすると丸ごと消える
GetSelectIncludeResult<P, A> Mapped Typesの値側を見ていく
GetSelectIncludeResult<P, A> Payload型を参照して、selectする値の型を取る
おさらい:$XxxPayload型 select結果の型を決定するためのマスタ schema.prisma 生成される型
GetSelectIncludeResult<P, A> scalarsではなくobjectsの場合も同様に取り、再帰的にselect結果を導出
GetSelectIncludeResult<P, A> 条件型に当てはまらなければneverに落とすが、最初の型制約で先に落ちるはず
まとめ:型パズルのエッセンス 型パズルを要素分解すると組み立てやすq Uf 型引数の推論によって入力の型を得 Df 型引数の制約を につけ E インターナルな型引数は補完不要なので頑張らなくて良q Bf
入力の型を条件型で絞り込みながら出力の型を組み立て E 事前生成したマスタ型(Payload)を参照してシンプル化 入力時の補完・エラーのため
型パズルをできるだけ頑張らない
なるべく事前生成して型計算を避ける Payload型から型パズルで導出できそうだが 重複を許容してすべて静的にコード生成する
なるべく事前生成して型計算を避ける モデルの一般化もせず重複生成
なるべく事前生成して型計算を避ける 事前生成ファイルは基本編集しないので、パースコストの影響が限定的 → ファイルサイズが大きくなってもOK 型チェックはfindFirstとかを触るたびに発生する(tsc内部でキャッシュは効くが) → パフォーマンスがDXに直撃する さらにビルド時間でもパースに比べて型チェックのほうが影響が大きい prisma/prisma の
tsc trace パース時間 型チェック時間
なるべく事前生成して型計算を避ける リアルタイムな入力に対してフィードバックしたい部分に絞って型計算をする その他はできるだけ静的にコード生成する
コード生成もできるだけ頑張らない
None
None
コード生成するコードは基本的につらい テンプレートリテラルなりASTビルダなりで組み立てるので見通しは最悪 なるべく生成するパターンを減らしたい
ライブラリとして切り出す 生成するコードのうち静的な部分はライブラリに切り出して、 生成コードからは参照するだけ 生成したコード
ライブラリとして切り出す Tips: ライブラリ内で使っているinternalな型もすべてexportする exportしていないと、この型を参照する他パッケージの.d.tsに インライン化されて爆発する Ref: https://github.com/prisma/prisma/blob/main /packages/client/src/runtime/core/types/exported/README.md
型以外は生成しない 生成された .d.ts 3500行に対して .js は200行程度 コード生成で頑張るのではなく Proxy を使った動的操作をしている
まとめ H リアルタイムな入力にフィードバックしたい部分だけは型パズルを頑張5 H 型パズルを要素分解して順番に考えるとやりやすF H それ以外はコードの重複を許容して事前生成に振り切5 H 完全に静的な型は生成すらせずライブラリÆ H
型以外のランタイム処理はProxyで頑張る
Thanks! Ubieのブースにいます!