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 の class を使い倒す
Search
Takuya Eguchi (egch)
July 22, 2024
Technology
56
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TypeScript の class を使い倒す
Takuya Eguchi (egch)
July 22, 2024
More Decks by Takuya Eguchi (egch)
See All by Takuya Eguchi (egch)
Next.js に疲れた私は Vue3 に癒やされた
egch
0
330
Secure な UX のために Content Security Policy について知っておこう
egch
0
64
package.json がすごい
egch
0
150
Nuxt.js のインスタンスライフサイクル総点検
egch
0
420
Webエンジニアのデザイン実装との付き合い方
egch
0
320
20200528 - GCPでもサーバーレスでRubyりたい!
egch
0
140
VeeValidate の"穴"を踏み抜いてしまった
egch
1
920
継続的に楽しくプログラミングするには - 2018/11/3 Rails Girls Sendai
egch
0
120
Other Decks in Technology
See All in Technology
新しい SLO が良い感じにハマっている話
z63d
5
2.2k
Forza Horizon 6 のテレメトリ機能で 自動運転に使えそうな学習データを集める話
henjin0
0
150
攻撃と防御で学ぶAI時代のプロダクトセキュリティ演習
recruitengineers
PRO
8
2.2k
SO-101×VLAによる3色キューブのピック&プレース
abeja
0
160
SmartHR Engineering Team Deck
smarthr
1
1.5k
【CEDEC2026】『Relink』を拡張せよ - 『GRANBLUE FANTASY: Relink - Endless Ragnarok』の開発速度と品質を守るCI運用
cygames
PRO
0
140
20260807_第6回_関東kaggler会LT_claw系bot xangiと始める、"寂しくない" kaggle
sugupoko
0
220
FPGAが実現する遠方宇宙の高空間分解能天体撮影 -大型地上望遠鏡の視力を補正する「補償光学」とは?-
komei_mt
0
190
今こそ聞きたいソフトウェア設計 ドメイン駆動設計再入門
masuda220
PRO
17
6.9k
Flutterをカメラで動かしたかった話
sony
1
130
AIエージェントを前提としたプラットフォーム エンジニアリング:GKEで作るAgent-Ready Golden Path
legalontechnologies
PRO
2
220
AI駆動開発は個人技からチーム戦へ:組織でAIを使いこなすための実践設計
moongift
PRO
0
480
Featured
See All Featured
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Marketing to machines
jonoalderson
1
5.7k
BBQ
matthewcrist
89
10k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
530
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
360
Skip the Path - Find Your Career Trail
mkilby
1
180
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
450
Context Engineering - Making Every Token Count
addyosmani
9
1k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Designing for humans not robots
tammielis
254
26k
How to train your dragon (web standard)
notwaldorf
97
6.7k
Transcript
TypeScript の Class を使い倒す 💪 2024/07/22 Sendai Front-End User Group
自己紹介 江口 拓弥 SFEUG 運営メンバーの1人 2018年に東京から仙台に移住 2019年から複数プロジェクトの新規事業開発やってます 1児の父です👶 akathea_
😢 こんなことありませんか? 1. API の response 型を バックエンドとフロントエンド 両方で定義するのが辛い 2.
フロントエンドでもバックエンドでも 値のバリデーション処理を書くのが辛い
A. GraphQL
おわり
✋ ちょっとまった!
Monorepo はどうだろう? @sick-project @sick-project/dto @sick-project/next @sick-project/nest get-foo.ts post-bar.ts
パッケージ module moduleResolution ESNext Bundler CommonJS NodeNext (target: ES2021から) @sick-project/dto
? ? このアイデアの問題点 型の提供だけならそれでよいが、 NestJS 側で swagger や class-validator 等を使うとき DTO は class として定義が必要 → tsconfig が異なるためどうビルドすればいいのか...
💡 マルチバンドルすればいいのでは?
前回の LT で話した内容を参考に https://speakerdeck.com/akagire/package-dot-json-gasugoi
こんな感じを妄想🤔 @sick-project @sick-project/dto @sick-project/next @sick-project/nest dist get-foo.js post-bar.js src get-foo.ts
post-bar.ts es get-foo.js post-bar.js type get-foo.d.ts post-bar.d.ts
パッケージ module moduleResolution ESNext Bundler CommonJS NodeNext (target: ES2021から) @sick-project/dto
CommonJS NodeNext tsconfig の設定は NestJS に寄せた
package.json と tsconfig.json を環境ごとに用意... @sick-project/dto src es dist package.json tsconfig.json
tsconfig.es.json { "exports": { ".": { "browser": "./es/index.js", "default": "./dist/index.js" } }, "types": "./dist/index.d.ts", "scripts": { "build:backend": "tsc -p tsconfig.json", "build:frontend": "tsc -p tsconfig.es.json" } } { "compilerOptions": { “module”: “CommonJS”, “target”: “ES2021” } } { "compilerOptions": { “module”: “ESNext”, “moduleResolution”: “NodeNext” } } ※tsconfigはだいぶ端折ってます
🎉 import できた! @sick-project/next/fetchFoo.ts import type { GetFoo } from
‘@sick-project/dto’; // 略 const res = await fetch(‘/foo’); const body: GetFoo = await res.body(); @sick-project/nest/foo-controller.ts import type { GetFoo } from ‘@sick-project/dto’; // 略 res.status(200).json<GetFoo>({ message: ‘foo’ });
😢 と、思っていたのか
es 向けビルド結果に decorator が混入 var __decorate = // 定義は略 import
{ ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty } from 'class-validator'; var GetFoo = /** @class */ (function () { function GetFoo () { } __decorate([ ApiProperty({ // description 等... }) IsNotEmpty() ], GetFoo.prototype, “type”, void 0); return GetFoo; }()); export { GetFoo }; この影響でフロントエンド環境に @nestjs/swagger, class-validator を入れないとビルドでエラー(ノ∀` ) →使いもしないのにインスコが必要で バンドルサイズ爆増
Strip Decorator https://www.npmjs.com/package/strip-decorators
ビルド結果 import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty
} from 'class-validator'; var GetFoo = /** @class */ (function () { function GetFoo () { } return GetFoo; }()); export { GetFoo }; 😢 decorator は消えたが、 import 文は消えてない dto の package.json へ “sideEffect”: false を指定で tree shaking されるが、 フロント側に @nestjs/swagger を install してないとビルドが通らない状況は変わらない class-validator をフロントエンドのリクエスト時のバリデーションで利用できなくなる
Strip Decorator の中身を覗いてみると... 👀
🤔 TypeScript Compiler API を使ってた https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API
TypeScript のトランスパイル処理をイジることができる サンプルとして、 • ES6 から d.ts ファイルの生成 • AST
を舐めて自作 linter を作る • moduleResolution のカスタマイズ などの魔改造コードが掲載されている
💡 これ使って 任意の decorator と import だけ 除去できるのでは?
😎 できた https://gist.github.com/akagire/38314038316c37afe115fd1025337af1
カスタムビルドの結果 Swagger に関する decorator だけ消すことができた →これでフロントエンドに @nestjs/swagger が不要になった! var __decorate
= // 定義は略 import { IsNotEmpty } from 'class-validator'; // 残ってる! var GetFoo = /** @class */ (function () { function GetFoo () { } __decorate([ IsNotEmpty() // 残ってる! ], GetFoo.prototype, “type”, void 0); return GetFoo; }()); export { GetFoo };
🤔 ・Compiler API は disclaimer にある通り なので、production で利用するのは心配 ・やりすぎてる感、やや難易度が高い印象 🎉
package.json × TypeScript × Compiler API を 組み合わせることで、互換性のない パッケージ間でも class をいい感じに共有! まとめ Keep in mind that this is not yet a stable API 💡 ・型共有の選択肢として十分ありだと思った ・フロントエンドのバンドルサイズ削減に 使えるかもしれない
おわり