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
僕が思い描くTypeScriptの未来を勝手に先取りする
Search
Yuku Kotani
September 06, 2024
Programming
10
2.8k
僕が思い描くTypeScriptの未来を勝手に先取りする
Web Developer Conference 2024
https://web-study.connpass.com/event/321711/
Yuku Kotani
September 06, 2024
Tweet
Share
More Decks by Yuku Kotani
See All by Yuku Kotani
Web技術を駆使してユーザーの画面を「録画」する
yukukotani
14
7k
Capacitor製のWebViewアプリからReact Native製のハイブリッドアプリへ
yukukotani
4
1.2k
Real World Type Puzzle and Code Generation
yukukotani
4
840
Kuma UI が提唱する Hybrid Approach CSS-in-JS の仕組み
yukukotani
2
500
GraphQLスキーマ設計の勘所
yukukotani
41
17k
既存Webサービスのモバイルアプリ版を 1週間でリリースし、進化させてきた話
yukukotani
0
690
先を見据えたMVPのフロントエンド開発
yukukotani
0
280
Bundle Side Optimization in Future JavaScript - JSConf JP 2021
yukukotani
2
2.9k
Kotlin/JS の仕組み / How KotlinJS works
yukukotani
5
3.1k
Other Decks in Programming
See All in Programming
見せてあげますよ、「本物のLaravel批判」ってやつを。
77web
7
7.7k
What’s New in Compose Multiplatform - A Live Tour (droidcon London 2024)
zsmb
1
470
リアーキテクチャxDDD 1年間の取り組みと進化
hsawaji
1
220
Contemporary Test Cases
maaretp
0
140
とにかくAWS GameDay!AWSは世界の共通言語! / Anyway, AWS GameDay! AWS is the world's lingua franca!
seike460
PRO
1
860
A Journey of Contribution and Collaboration in Open Source
ivargrimstad
0
910
TypeScript Graph でコードレビューの心理的障壁を乗り越える
ysk8hori
2
1.1k
Outline View in SwiftUI
1024jp
1
330
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
1
100
Generative AI Use Cases JP (略称:GenU)奮闘記
hideg
1
290
シェーダーで魅せるMapLibreの動的ラスタータイル
satoshi7190
1
480
Nurturing OpenJDK distribution: Eclipse Temurin Success History and plan
ivargrimstad
0
900
Featured
See All Featured
Statistics for Hackers
jakevdp
796
220k
GraphQLとの向き合い方2022年版
quramy
43
13k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.8k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.7k
GitHub's CSS Performance
jonrohan
1030
460k
Teambox: Starting and Learning
jrom
133
8.8k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.3k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
4
370
Bash Introduction
62gerente
608
210k
The Art of Programming - Codeland 2020
erikaheidi
52
13k
Visualization
eitanlees
145
15k
Transcript
僕が思い描く 勝手に TypeScriptの未来を 先取りする @yukukotani 2024/09/07 - Web Developer Conference
2024
自己紹介 小谷 優空 - @yukukotani ・VP of Technology @ Ubie,
Inc. ・Maintainer of KumaUI ・Student @ Univ. Tsukuba
今日の趣旨 Call-this operatorが好きすぎて僕だけ勝手に使っている話を延々とします 自由研究とか図画工作の類です
Call-this operator、なんなんじゃそりゃ Function.prototype.call の糖衣構文となる二項演算子 TC39で提案中のStage-1プロポーザル NEW!
Function.prototype.call、なんなんじゃそりゃ 任意の値をthisに束縛して関数を呼べる → Call-this operatorだと できる レシーバをthisに束縛
Function.prototype.call、なんなんじゃそりゃ 任意の値をthisに束縛して関数を呼べる → Call-this operatorだと できる レシーバをthisに束縛 そんなの使ったことないよ
いろいろな Function.prototype.call G プロトタイプ汚染の防6 G 組み込み関数のモンキーパッQ G メソッドの動的切り替! G etc...
いろいろな Function.prototype.call G プロトタイプ汚染の防6 G 組み込み関数のモンキーパッQ G メソッドの動的切り替! G etc...
僕らはそんなことしないよ
では僕たちアプリケーション開発者 にとって何がうれしいのか?
(1) classの代替
よくあるclassベースのモデル 抽象クラスUserには2種2 G RegisteredUser, AnonymousUser 両方からリソースのURLを取れる RegisteredUserだけはメールを送れる
TypeScriptのclassには色々なつらみがある classのメソッドはシリアライズ/デシリアライズできない(当然) Next.jsのServer Actionsのような境界で壊れがち user2.getUrl is not a function
TypeScriptのclassには色々なつらみがある TypeScriptの構造的部分型ではclassの名前が無視される 全く同じプロパティを持っていたら別クラスでも型が一致してしまう https://example.com/articles/foo UserにArticle代入できちゃう Userと全く同じシグネチャ idとgetUrl
TypeScriptのclassには色々なつらみがある classのメソッドにはDead Code Eliminationが効かず、バンドルサイズ肥大化 メソッドが依存する外部ライブラリ等のTree Shakeも芋ずる式に効かなくなる このメソッドは未使用なのに ビルド成果物に残ってしまう
TypeScriptのclassには色々なつらみがある そもそもclass一般の話題として、継承によるモデリングの限界も見えてきている https://speakerdeck.com/naoya/guan-shu-xing-puroguramingutoxing-sisutemunomentarumoderu?slide=54
人々はtypeと関数に救いを求めた G 振る舞いは純粋な関数として実8 G データはただのtypeとして定& G Tagged Unionで多態相当の表現
type+関数が結論なのか!? データはただのオブジェクトなのでシリアライズ・デシリアライズできる エラーにならない!
type+関数が結論なのか!? Tagged Unionのようにタグを付けておけば異なる型をちゃんと区別できる 発展的には Branded Type のようなテクニックもある エラー!kindが異なるので代入できない
type+関数が結論なのか!? Dead Code Elimination も当たり前に効く 未使用なので関数丸ごと消える
type+関数が結論なのか!? いいことづくしなのにclassを使い続ける人が多いのはなんでだろう
classのここが嬉しい! データに対する振る舞いが閉包的に定まる 普通に書けばデータそのものが振る舞いの名前空間となるから(prototype) userに対する振る舞いは getUrl, sendEmailに定まる
classのここが嬉しい! より直接的に言うと、レシーバを書いた時点でその振る舞いがわかる
type+関数だとメンタルモデルが異なる 関数ベースだと、まずグローバルな名前空間から振る舞いを探す必要がある (名前空間のためにオブジェクト作ったりするとTree Shakeできなくなる)
それ、Call-this operator でできるよ! レシーバにしたい型を This Parameter で定義 普通の引数の代わりに thisの型を定義
それ、Call-this operator でできるよ! 型が名前空間として機能し、 データ→型→振る舞い という紐付きで同定できる ~> を打ったタイミングで レシーバとThis Parameterを型検査
マッチするものだけ取り出せる
DEMO
(2) Tree Shake可能なユーティリティ
僕たちも嬉しい Call-this operator メソッドチェーンのDXとツリーシェイク可能なインポートの両立 zodとvalibotの良いとこ取りみたいなことができる 体験は良いけど Tree Shaking効かない 補完体験を維持しつつ Tree
Shakingも効く! Tree Shaking効くけど 補完体験が悪い
DEMO
よさそうなことはわかった 使いたい
Call-this operator、なんなんじゃそりゃ Function.prototype.call の糖衣構文となる二項演算子 TC39で提案中のStage-1プロポーザル NEW!
TC39? Stage 1? ECMAScriptの仕様を議論する委員会。仕様提案をStageに分けて管理している Stage 0 新しく提出されたプロポーザル。まだTC39の議論対象ではない Stage 1 Championと呼ばれる推進者が決まり詳細化されたプロポーザル。TC39の議論対象になる
Stage 2 セマンティクスや文法といった仕様の草案が定義され、その方向性に合意したプロポーザル Stage 2.7 仕様が決定し、原則承認されたプロポーザル。実装上の不都合がないかテストやプロトタイピングで検証する Stage 3 本番での実装が推 奨されるプロポーザル。実 世界で不都合がないか フィー ドバック を集める Stage 4 正式に承認されたプロポーザル。 ここか ら変更は 入らず、 次バー ジョンの EC MAScrip tに 含まれる
Babelプラグインで試したい Stage3以前の構文系の提案はBabelプラグインで試せるのが一般" D @babel/plugin-proposal-record-and-tuple (Stage 2 D @babel/plugin-proposal-throw-expressions (Stage 2)
@babel/plugin-proposal-throw-expressions
Babelプラグインじゃ足りなかった;; Babelはあくまでコードのトランスパイルだけやってくれる(当たり前) 今回は まで含めた開発体験を手触りしたい 補完や型検査
TypeScriptで試したい TypeScriptもまだブラウザで動かない新機能をサポートして ダウンレベルコンパイルしてくれる Explicit Resource Managementとか
TypeScriptにはまだ入らない;; TypeScriptはStage 3以降の提案のみを実装するポリシー Call-this operatorはまだStage 1 https://github.com/microsoft/TypeScript/blob/a709f989/src/lib/README.md
Stage 3に進めてもらい・・・たい・・・ https://github.com/tc39/proposal-call-this プロポーザルの最終コミットが1年前、tc39/agendas でも音沙汰なし
J.S. Choiさんが忙しそう Call-this operatorとかPipeline operatorのチャンピオン 本業は内科医なのにtc39とかUnicode Consortiumとかやってる謎の人 https://github.com/js-choi
標準化は待たずに 自由研究するしかない!
TypeScriptコンパイラを雰囲気で理解する https://github.com/microsoft/TypeScript-Compiler-Notes/tree/314256/intro 公式ガイドっぽいのがあったので斜め読み microsoft/Typescript-Compiler-Note
TypeScriptコンパイラを雰囲気で理解する https://github.com/microsoft/TypeScript-Compiler-Notes/tree/314256/intro 公式ガイドっぽいのがあったので斜め読み microsoft/Typescript-Compiler-Note
トークナイザの実装 入力したコードを意味のある単位で区切った配列にする 今回は新しいトークン `~>` が登場するので対応が必要 NEW!
トークナイザの実装 作戦:似たようなトークンを見つけて追いかける ./src/compiler/types.ts
トークナイザの実装 雰囲気でトークンを定義する ./src/compiler/types.ts ./src/compiler/scanner.ts
トークナイザの実装 すでにチルダをconsumeしてるところがあったので雰囲気で付け加える ./src/compiler/scanner.ts
トークナイザの実装 それっぽくトークナイズできた!
TypeScriptコンパイラを雰囲気で理解する https://github.com/microsoft/TypeScript-Compiler-Notes/tree/314256/intro 公式ガイドっぽいのがあったので斜め読み microsoft/Typescript-Compiler-Note
パーサの実装 トークン列を木構造(AST)に変換する
ASTを考える パーサーが吐くAST構造を考えるために、既存の似ている構文を観察する globalThis.window.closeまではPropertyAccessExpressionで それを呼び出すとCallExpressionで包まれる
ASTを考える Call-this expressionも同じ構造でいけるか? → `~>` があるなら () で呼び出さないと構文エラーなのでちょっと違う。
ASTを考える レシーバから呼び出し部分まで1つのノードに入れて、 PropertyAccessExpressionとCallExpressionの合いの子みたいにする receiver expression typeArguments arguments
パーサの実装 parser.ts から実装箇所を探したいが、1万行あるのでエスパーが必須 → 仮説: `expr.name` のピリオド解析時に PropertyAccessExpression を 作っているところに相乗りできないか?
パーサの実装 それっぽい関数があった。`expr.name` の `.name` の部分を解析していそう ここから親にたどってみる
パーサの実装 `expr.name?.foo.bar` みたいなチェーンを再帰的に解析している関数があった ここに相乗りできそう!
パーサの実装 `~>` があったら CallThisExpressionとして解析するようにして完了
TypeScriptコンパイラを雰囲気で理解する https://github.com/microsoft/TypeScript-Compiler-Notes/tree/314256/intro 公式ガイドっぽいのがあったので斜め読み microsoft/Typescript-Compiler-Note
エミッタの実装 ASTをJavaScriptとして出力する
エミッタの実装 CallThisExpressionノードの子ノードを順番に出力していくだけ
嬉しいですね 入力したTypeScriptを解釈してJavaScriptに出力するところまで一通り動いた!
嬉しくない Call-this parameterを解釈できるJavaScriptランタイムはたぶんない(それはそう)
トランスフォーマの実装 ./src/transformers 配下に target ごとの実装があり、 visitor pattern で変換している 今回は esnext.ts
に足していく
トランスフォーマの実装 `receiver.fn(arg)` を `fn.call(receiver, arg)` に変換。 既に色々なfactoryがあるので組み立てるだけ
嬉しいですね 一般的なランタイムで動くJavaScriptを出せた!
嬉しくない せっかくTypeScriptなのにぶっ壊せちゃう
型チェッカの実装 5万行のクソデカ型チェッカ checker.ts をどうにかする This parameterとレシーバの型の一致をチェックする以外は 普通の関数呼び出しと同じなのでパクって実装する 変更でかいので気になる人はコミット見てください(雑) https://github.com/microsoft/TypeScript/pull/58294/commits/ ce12997edd2302325e1463ec1554ae006d8ec3b3
嬉しいですね レシーバの型エラーが出るようになった
補完も効かせたい VSCodeのTypeScript ExtensionからTS Serverに補完依頼がくる VSCode TS Server `>` で補完だしたいのだが こちらのリストでございます!
補完も効かせたい まずExtension側で `>` でも補完を呼び出すようにする TypeScript Extensionは特別にVSCodeに組み込まれているので microsoft/vscode に手を入れる ./ extensions/typescript-language-features/src/languageFeatures/completions.ts
NEW!
補完も効かせたい TypeScript (TS Server) 側ではまず `>` が Call-this なのか確かめる じゃないと普通の比較演算とかでも補完がでて困っちゃう
補完も効かせたい 補完リストは以下のロジッR まずグローバルな関数呼び出しと同様のをリストアッ( その中からレシーバとThis Parameterが一致する関数に絞る
嬉しいですね 補完が効きます
DEMO
まとめ 5 Call-this operator が来るととても嬉しいで8 5 TypeScriptに変更を加えると新規機能が実装できて楽しいです
ありがとうございました