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
UIパーツの設計を「型」から読み解く 〜TSKaigiのセッションから得た学び〜
Search
yud0uhu
June 25, 2026
Technology
270
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
UIパーツの設計を「型」から読み解く 〜TSKaigiのセッションから得た学び〜
TSKaigi 2026事後勉強会の登壇資料です。
https://smarthr.connpass.com/event/392342/
yud0uhu
June 25, 2026
More Decks by yud0uhu
See All by yud0uhu
美しいコードを書くためにF#を学んでみた話
yud0uhu
1
410
未必のマクベス
yud0uhu
0
48
Webブラウザ向け動画配信プレイヤーの 大規模リプレイスから得た知見と学び
yud0uhu
0
390
早朝の渋谷の青さ、あるいは溺れた人を助ける為に飛び込んだ海の向こう側に見る、自己覚知と自己開示の尊さ
yud0uhu
1
980
動画配信サービスのフロントエンド実装に学ぶ設計原則
yud0uhu
1
390
非デザイナーのフロントエンドエンジニアがOOUIを考える
yud0uhu
9
6k
2023年の ゼロランタイムCSS in JS⚡️ を考える
yud0uhu
5
5.1k
Vue3/Electronで自作したマークダウンエディタをVue3/Tauriにリプレイスした話
yud0uhu
2
3.2k
入社半年を迎える新米エンジニアがカンファレンス・勉強会から得た学び
yud0uhu
0
1.1k
Other Decks in Technology
See All in Technology
SREとQA 二人三脚で進めるSLO運用/sre-qa-slo
sugitak
0
440
Gen3R: 3D Scene Generation Meets Feed-Forward Reconstruction
spatial_ai_network
0
110
Claude Codeとハーネスについて考えてみる
oikon48
18
9.3k
穢れた技術選定について
watany
3
300
AI時代のエンジニアキャリアについて今一度考える
sakamoto_582
2
1.5k
Foxgloveについて 実際にExtensionを開発して公開するまでの話 / About Foxglove: The Story of Developing and Releasing an Extension
ry0_ka
0
210
AI Agent SaaS を支える自社仮想化基盤への挑戦と実運用 / ai-agent-saas-virtualization
flatt_security
2
3.8k
証券システムを10年Scalaで作り続けるということ - 関数型まつり2026
krrrr38
3
840
Claude Code公式skillで 自分の仕事を少しずつ手放そう!(Claude Code開発ノウハウ大公開スペシャル by クラスメソッド)
kaym
1
240
地域 SRE コミュニティ最前線 / SRE NEXT 2026 Discussion Night Track C
muziyoshiz
0
210
CSに"SLO"は要らない、経営層に"99.9%"は伝わらない - SREを全社に"翻訳"する3原則
cscengineer
PRO
1
4.5k
しくみを学んで使いこなそう GitHub Copilot app
torumakabe
2
230
Featured
See All Featured
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.9k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
RailsConf 2023
tenderlove
30
1.5k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
610
sira's awesome portfolio website redesign presentation
elsirapls
0
300
KATA
mclloyd
PRO
35
15k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
How to Ace a Technical Interview
jacobian
281
24k
Documentation Writing (for coders)
carmenintech
77
5.4k
Un-Boring Meetings
codingconduct
0
340
Docker and Python
trallard
47
3.9k
Into the Great Unknown - MozCon
thekraken
41
2.6k
Transcript
UIパーツの設計を「型」から読み解く 〜TSKaigiのセッションから得た学び〜 0yu @yud0uhu 2026/06/25(Thu) TSKaigi 2026事後勉強会
自己紹介 0yu(おゆ) Web FE 好きなもの 推理小説、映画、謎解き・マダミス、ウイスキー @yud0uhu @yud0uhu
TSKaigiのセッションから得た学び
出典:React の props は値の集合ではない — UI の状態を宣言するコンポーネント設計(nabeliwo)さん
TSKaigiのセッションから得た学び UIパーツの設計を「型」から読み解く 同セッションの具体例として挙げられていた状態
出典:「進研ゼミでやったところだ!」現象|西川智希. note. https://note.com/nishikooooth/n/n9727b86bd772
様々な状態を持つUIパーツを propsで表現する
様々な状態を持つアイコンをpropsで表現する 課題 用途に応じて様々な状態を表現する「AnimationIcon」を再設計したい 「ToggleIcon」の名前で共通化された「AnimationIcon」が存在する お気に入り(オン/オフ) 再生/停止 ミュート/解除 10秒戻す、10秒進める
様々な状態を持つアイコンをpropsで表現する アイコンの責務と状態(振る舞い)の整理 すべてのアイコンに共通する振る舞い 「押下したこと」がアニメーションとしてフィードバックされる アイコンごとに異なる振る舞い トグルするアイコン(押下するとアイコンが変わる) 例:お気に入り(オン/オフ)、再生/停止、ミュート/解除 トグルしないアイコン(押下してもアイコンは変わらない) 例:10秒戻す、10秒進める
Before
Before Before 1 2 3 4 5 6 7 8
9 10 11 // 「トグルするアイコン」と // 「トグルしないアイコン」の責務が混在している type Props = { isShrinking: boolean; iconComponent: React.ReactNode; // トグルアイコンなのに、トグルしないアイコンが存在する previousIconComponent?: React.ReactNode; // アニメーションをさせるためだけに存在する handleShrinkComplete: () => void; handleGrowComplete: () => void; };
Before リファクタ前のコードの持つ問題点 「コード(型)が仕様を表現しきれていない」 実装者に誤った使い方を誘引してしまう
After
After 「discriminated union」でUIの振る舞いを型に閉じ込める 1 2 3 4 5 6 7
8 9 10 11 12 13 type ToggleProps = BaseProps & { type: "toggle"; isToggled: boolean; fromIcon: React.ReactNode; toIcon: React.ReactNode; }; type NonToggleProps = BaseProps & { type: "non-toggle"; icon: React.ReactNode; }; type Props = ToggleProps | NonToggleProps;
After Propsでアイコンごとの責務を分離する 1 2 3 4 5 6 7 8
9 export type BaseBouncyIconProps = { onClick: () => void; onAnimationEnd?: () => void; className?: string; }; export type PlayToPauseBouncyIconProps = BaseBouncyIconProps & { isPlaying: boolean; };
After JSXの構造でUIの状態を表現する 1 2 3 4 5 6 7 8
9 10 11 12 type ToggleProps = BaseProps & { // ... fromIcon: React.ReactNode; toIcon: React.ReactNode; }; return ( <BaseBouncyIconButton // ... fromIcon={<IconPlay className="size-full" />} toIcon={<IconPause className="size-full" />} />
「discriminated union」で UIの振る舞いを型に閉じ込める
「discriminated union」でUIの振る舞いを型に閉じ込める 「discriminated union」でUIの振る舞いを型に閉じ込める 1 2 3 4 5 6
7 8 9 10 11 12 // 不可能な状態を許容してしまう type BadProgressBarProps = { status: 'loading' | 'success' | 'error'; percent?: number; // loadingの時だけほしい message?: string; // errorの時だけほしい }; // 判別可能なユニオン型 type GoodProgressBarProps = | { status: 'loading'; percent: number; } | { status: 'error'; message: string; } | { status: 'success'; };
「シンプル」が至上
「シンプル」が至上 「シンプル」が至上 「いかに削ぎ落とすか、公開するものを減らすか」を考える ex.「判別可能なユニオン型」によるカプセル化でスコープを閉じる アニメーションする責務が外側から介在しなくなる
オブジェクト指向から考える 「カプセル化」と「命名」
オブジェクト指向から考える「カプセル化」と「命名」 オブジェクト指向から考える「カプセル化」と「命名」 “オブジェクト指向を超えて重要な原則は 「カプセル化」と「正しい名前付け」” ➖ オブジェクト指向と10年戦ってわかったこと | https://qiita.com/tutinoco/items/6952b01e5fc38914ec4e
オブジェクト指向から考える「カプセル化」と「命名」 オブジェクト指向から考える「カプセル化」と「命名」 「discriminated union」による「カプセル化」 単にPropsを共通化するのではなく、UIの振る舞い(ドメイン)を正し く型に落とし込む(モデリングする) 不可能な状態を型で許容しない 「正しい名前付け」による「関心の分離」 「アニメーションという振る舞い」と 「トグルする/しないというロジック」を分離して考える
ToggleIconはToggleIconではなかった
オブジェクト指向から考える「カプセル化」と「命名」 オブジェクト指向から考える「カプセル化」と「命名」 「discriminated union」による「カプセル化」 単にPropsを共通化するのではなく、UIの振る舞い(ドメイン)を正し く型に落とし込む(モデリングする) 不可能な状態を型で許容しない 「正しい名前付け」による「関心の分離」 「アニメーションという振る舞い」と 「トグルする/しないというロジック」を分離して考える
ToggleIconはToggleIconではなかった
まとめ
まとめ まとめ UIコンポーネントの設計では、Propsのデータ型そのもので仕様(UIの振 る舞い)を表現し、使う側の認知負荷を減らすのが理想 UIごとの責務の分離と、「引き算」を意識する 実業務で先輩から学んだ設計の話とセッションの内容が重なり、ユース ケース的な学びが大きかった💪