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
型安全なDrag and Dropの設計を考える
Search
yudppp
May 23, 2025
Programming
1.1k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
型安全なDrag and Dropの設計を考える
TSKaigi 2025のLT資料
yudppp
May 23, 2025
More Decks by yudppp
See All by yudppp
開発者にもコーディングエージェントにも働きやすい環境を整える
yudppp
1
170
未知のプログラミング言語にChatGPTと共に挑む
yudppp
0
560
SaaSフロントエンド開発の現場で求められる技術 / Technologies for SaaS Frontend Development in the Field
yudppp
2
300
2019年 HRBrainの技術的挑戦 / hrbain technology challenge 2019
yudppp
3
1.5k
Web開発を支えるマイグレーションツールについて / sqldef introduction for psql users
yudppp
2
3.7k
ISUCON向けのツールを作った話 / isutools
yudppp
1
360
Row Level Securityはマルチテナントの銀の弾丸になりうるのか / Row Level Security is silver bullet for multitenancy?
yudppp
23
34k
Webサービス開発に必要な統計学入門 / study of statistics for web developers
yudppp
1
380
メジャーな Live Reloaderの違いをちゃんと調べて見た / Compare major live reloader of Go
yudppp
1
2k
Other Decks in Programming
See All in Programming
dotNET_vulnclicker_intro.pdf
deka_morita
0
140
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
2.2k
TechTown - Creating Composable Callables in Contemporary C++
rollbear
0
120
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
35
16k
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
170
AIに “答え“を書かせるのを やめてみた
___akari11
0
120
AI主導のプログラミング学習アプリを作ってみた
econanringo
0
180
個人開発者よ、Honoを使え(おじさんver)
tanahiro2010
2
260
SREの越境 / SRE Collaboration
y0hgi
2
310
機械に任せるテスト、人が見るテスト ⽣成AIで引き直した、運⽤保守フェーズの線引き
dske104
0
190
月間100万人のサービス刷新で、 技術選定をHonoに振り切った話
yutobara
8
6.6k
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
350
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
42
3.2k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
WENDY [Excerpt]
tessaabrams
14
40k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
280
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
580
Are puppies a ranking factor?
jonoalderson
2
4k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
7k
Mind Mapping
helmedeiros
1
400
4 Signs Your Business is Dying
shpigford
187
23k
Facilitating Awesome Meetings
lara
57
7.2k
Transcript
型安全なDrag and Dropの設計を考える TSKaigi 2025
株式会社HRBrain 執行役員CTO 2018年に HRBrain に 10人目の社員、3人目のエンジニアとして 入社。TypeScriptも2018年からはじめました。 今もバックエンドとフロントエンドのプロダクションのコードを 本当にたくさん書いてます。 yudppp
について HRBrain は「タレントマネジメント」「人事評価」「組織診断サーベイ」「労務管理」など 8種類のプロダクトを提供し ており、人事の様々な業務を効率化し、蓄積されたデータを活用して効果的な人事戦略を実現するためのタレントマネジ メントシステムです。 SaaSは一つのアプリケーションを、複数の会社、複数の運用を担う必要があるため、カスタマイズ性が求められます。カ スタマイズを直感的に扱えるようにするため、Drag and
Dropを利用しています。
利用例 例えば、管理する従業員の情報を設定 する画面で利用しています。 項目とグループといったドラックでき るオブジェクトがあり、どこにおける かはドラックしているオブジェクトの 情報とドラッグされる場所の情報、状 態によって変わっていきます。 このようなシンプルなリストの並び替 え以外のことをすることが多いです。
Drag and Dropの失敗例 V ドラッグした要素の消S V ドラッグした瞬間にページが真っ白にな$ V インプット付きのアイテムの場合に、中のテキストが元の場所に居残る
Drag and Dropの失敗例 t ドラッグした要素の消s t ドラッグした瞬間にページが真っ白になC t インプット付きのアイテムの場合に、中のテキストが元の場所に居残る ↓↓e
t ドラッグしている要素と、置く要素の関係の定義が漏れていることが多い
ドラッグできるオブジェクト 項目 グループ
ドラッグできるオブジェクト 項目 グループ
ドロップできる場所 項目 グループ
ドロップできる場所 項目 グループ
これを型に落とし込んでいく
型の定義 ① // ドラッグする型の定義 // ドロップする場所の定義 // 全体のレイアウト export interface
extends = : : export interface extends = : : export interface < , > { ; ; } < , > { ; ; } {} DraggableItem T P T P DropAreaItem T P T P LayoutData string unknown string unknown type payload type payload
型の定義 ② // ItemとTargetの組み合わせで置けるのか、置いたときどうなるのか // 「移動元→移動先」という文字列にする // 「移動元→移動先」のすべての組み合わせごとに必ずルールを定義するようにする export interface
extends extends : : : : => : : : : => | type extends extends = export type extends extends = in : extends infer extends infer extends ? : < < , >, < , >, > { ( , , ) ; ( , , ) ; } { : ; } < < , >, < , >, > ; < < , >, < , >, > { [ < , >] < < , < , >>, < , < , >>, > ; }; Rule Item DraggableItem Target DropAreaItem LayoutData canDrop Item Target LayoutData onDrop Item Target LayoutData LayoutData canDrop RuleKey Item DraggableItem Target DropAreaItem Item Target RuleSet Item DraggableItem Target DropAreaItem LayoutData K RuleKey Item Target K IT Item TT Target Rule Extract Item DraggableItem IT Extract Target DropAreaItem TT LayoutData any any any any boolean false any any any any any any any any any any never item target layoutData item target layoutData `${ ["type"]}→${ ["type"]}` `${ ["type"]}->${ ["type"]}`
型の定義 ③ export class extends extends : : : :
=> : : : => constructor : : = = : : => const = return as as = : : => if ! return const = as as < < , >, < , >, > { ; ( , ) ; ( , ) ; ( , < , , >) { .data initialData; . ( , ) { ruleSet[ (item, target)]; rule. (item , target , .data); }; . ( , ) { ( . (item, target)) .data ruleSet[ (item, target)]; this.data = rule. (item , target , .data); }; } } Layout Item DraggableItem Target DropAreaItem LayoutData LayoutData canDrop Item Target onDrop Item Target LayoutData RuleSet Item Target LayoutData canDrop Item Target getRuleKey canDrop onDrop Item Target canDrop getRuleKey onDrop any any any any boolean void this this rule any any this this this this rule any any this data item target item target initialData ruleSet item target item target ※発表用に簡略化しています(本当はcanDrop === falseの対応とか必要)
使い方 ① // 全体のデータをどう持つか { [] } // ドラッグできるものの定義 <
, >; < , >; ; < , >; // 行と行の隙間で新しい行作るときのやつ < , { groupId: string, index: number }>; ; type = : type = type = type = | type = type = type = | LayoutData Group DraggableFieldItem DraggableItem Field DraggableGroupItem DraggableItem Group AnyDraggableItem DraggableFieldItem DraggableGroupItem RowDropArea DropAreaItem Row InsertRowDropArea DropAreaItem AnyDropAreaItem RowDropArea InsertRowDropArea groups "field" "group" "row" "insertRow" // ドロップできる場所の定義
使い方 ② // 何がどこに置けて、置けたらどうなるのか < , , > { :
{ : ( , , ) target.fields. , : ( , , ) xxxx, }, : { : ( , , ) , : ( , , ) xxxx, }, : { : }, : { : ( , , ) , : ( , , ) xxxx, }, }; const : = => < => => => => => layoutRules length 6 true false true RuleSet AnyDraggableItem AnyDropAreaItem LayoutData canDrop onDrop canDrop onDrop canDrop canDrop onDrop 'field->row' 'field→insertRow 'group->row' 'group->insertRow' item target layout item target layout item target layout item target layout item target layout item target layout // 対象行の項目数が6未満だったら追加可能 // 頑張りどころでitemがtargetに移動したときにどうlayoutが変更されるか // 常に追加可能 // 常に不可 // 常に追加可能
使い方 ③ export class extends constructor : --- const =
new --- --- < , , > { ( ) { (data, layoutRules); } } (data) layout. (item, area) layout. (item, area) Layout LayoutState AnyDraggableItem AnyDropAreaItem LayoutData LayoutData Layout canDrop onDrop data super layout
結局我々がやるべきこと ドラッグ可能なアイテムの種類とドロップエリアの種類と、持つべきデータを定R 置けるのか置けないのか、置いたあとにどう変化するかを表すRuleを本気で実装すG 新しいアイテムが追加されたときに、実装漏れがないような作りにするこt Viewの作り込みと分離することで、集中する領域を切り離すこt
今回は話せていないが、あとはView側では当たり判定の範囲を綿密に計画する