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
TypeScriptでType Match的なことをする話 #すえなみチャンス暑気払い
Search
kyo_ago
August 04, 2019
Programming
1.4k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TypeScriptでType Match的なことをする話 #すえなみチャンス暑気払い
kyo_ago
August 04, 2019
More Decks by kyo_ago
See All by kyo_ago
フロントエンドの リソース管理の話 TechFeed Summit#1 #techfeed #techfeedsummit
kyo_ago
5
2k
WebReplayから見るWeb開発の未来 #builderscon
kyo_ago
2
1k
今日から始めるbugbounty
kyo_ago
0
320
karmaを使ったSPA向けE2Eテスト技法
kyo_ago
6
5.8k
E2Eという名称の指すもの
kyo_ago
0
2.7k
How to use Scala.js in real world?
kyo_ago
1
2.2k
Other Decks in Programming
See All in Programming
私なりのハーネスエンジニアリング ~独自の言語処理系の開発を通して~
seosoft
0
110
When benchmarks go bad - what I learned from measuring performance wrong
hollycummins
0
250
Spec-Driven Development - Why Vaadin Is the Perfect Fit
simas
PRO
0
150
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
200
コーディング自動化の次へ。人の介入をゼロにするファクトリーとサポートAIによる実践
timakin
5
4.8k
パスワード再設定メールのURLについて知っておこう
uyuki234
0
190
AIが生成したコードは読むべきか?抽象化設計とコードの品質保証 / abstraction-design-and-quality
minodriven
11
7k
Next.js: The final boss of Web Performance
guaca
0
350
graphql-ruby を Spinel で速くしようとした話
mtsmfm
0
120
APNsからLive Activityを開始する話
yumnumm
0
180
続・コーディングルールの鮮度を保ちたい / keep-fresh-go-internal-conventions-again
handlename
0
130
AI時代のTerminal環境を UNIX哲学で設計・運用する
yasunori0418
1
290
Featured
See All Featured
[SF Ruby Conf 2025] Rails X
palkan
3
1.5k
Designing for Timeless Needs
cassininazir
1
530
We Have a Design System, Now What?
morganepeng
55
8.4k
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.2k
Designing Experiences People Love
moore
143
24k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
720
GraphQLとの向き合い方2022年版
quramy
50
15k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
650
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
490
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
2
950
StorybookのUI Testing Handbookを読んだ
zakiyama
31
7k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
530
Transcript
5ZQF4DSJQUͰ5ZQF.BUDIత ͳ͜ͱΛ͢Δ ͑͢ͳΈνϟϯεॵؾ͍ !LZP@BHP
݁
TFBMFEDMBTT PSUSBJU Λ͍·͠ΐ͏ 4DBMBͷ
ຊ
͜ΕԿʁ
5ZQF4DSJQUͷ4USJOH-JUFSBM5ZQFTΛͬͨ ঢ়ଶͷཧ$IBUXPSL$SFBUPST/PUF ͷվม൛Ͱ͢ɻ
ԿΛղܾ͍ͨ͠ͷ͔
ෳࡶͳঢ়ଶɺ݅ذΛ༰ қʹѻ͑ΔΑ͏ʹ͍ͨ͠ ʢෳࡶͳঢ়ଶɿCPPMFBOͭͱ͔Ͱཧͯ͠ΔΑ͏ͳͷʣ
۩ମతʹ
// ਏ͍ྫ class Message { constructor( private sending: boolean, private
editing: boolean, private deleted: boolean, ) {} canEdit(): boolean { if ( !this.sending && !this.deleted ) { return false; } return true; } }
͞Βʹ
// ͬͱਏ͍ྫ class Message { constructor( private sending: boolean, private
loading: boolean, // New! private editing: boolean, private deleted: boolean, ) {} canEdit(): boolean { if ( !this.sending && !this.loading && // New! !this.deleted ) { return false; } return true; } }
Կ͕ͳͷ͔
w ঢ়ଶͷΈ߹Θ͕ͤ݅ذΛΈͳ͍ͱஅͰ͖ͳ͍ w ݅ذͷJG͕ෳࡶ w ม͕Ճ͞Εͨ߹ͷཏੑͷอূ͕͍͠
// ਏ͍ྫ class Message { constructor( private sending: boolean, private
loading: boolean, // New! private editing: boolean, private deleted: boolean, ) {} canEdit(): boolean { if ( !this.sending && !this.loading && // New! !this.deleted ) { return false; } return true; } }
DMBTTNFUIPEͰ݅ذΛߦ͏ͱɺʮಛఆͷঢ় گԼͰDMBTT͕Ͳ͏͍͏ঢ়ଶʹͳΔ͔ʁʯͷஅ͕͘͠ ͳΔɻ ݅ذͦͷঢ়ଶʹ໊લΛ͚ͭͳ͍ͨΊɺʮ݅ذ ʹҰக͢ΔͷͲ͏͍͏ঢ়ଶ͔ʁʯʹର͢Δղऍ͕ᐆດ ʹͳΔɻ ʢ͜ͷ߹ɺDBO&EJUʮฤूՄೳͳঢ়ଶʯͰҰக͢Δ ͱࢥ͏͚Ͳʣ
// ֎෦͔Βݟͯಉ͡ঢ়ଶ͔ʁ const message = new Message(/.../); const getEditableMessage =
() => { return message.canEdit() ? "मਖ਼Ͱ͖ΔΑʂ" : "मਖ਼ Ͱ͖ͳ͍Αʂ"; } const showEditableIcon = () => { return message.canEdit(); }
ྫ͑ɺ৽͘͠ʮJT4FDSFUʯͱ͍͏มΛՃ͠ ͨ߹ɺDBO&EJUʹӨڹ͢ΔͩΖ͏͔ʁ ·ͨɺӨڹ͢Δͱͯ͠ɺDBO&EJUΛݺͼग़͍ͯ͠ Δଆಉ͡ఆͩΖ͏͔ʁ
Ͳ͏ղܾ͢Δͷ͔
ঢ়ଶΛDMBTTԽ͢Δ
// ָͳྫ type MessageStateLiterals = "sending" | "loading" | "editing"
| "deleted"; class MessageState { private state: MessageStateLiterals; constructor( sending: boolean, loading: boolean, editing: boolean, deleted: boolean, ) { // ݅ʹԠͯ͡this.stateMessageStateLiteralsͷ͍ͣΕ ͔Λೖ } match<R>(matcher: { [key in MessageStateLiterals]: () => R }): R { return matcher[this.status](); } }
͍ํ
class Message { private state: MessageState; constructor( private sending: boolean,
private loading: boolean, private editing: boolean, private deleted: boolean, ) { this.state = new MessageState(true, false, false, false); } canEdit(): boolean { return this.state.match({ "sending": () => false, "loading": () => false, "editing": () => true, "deleted": () => false, }); } }
ར
ར w ঢ়ଶͷஅʹؔΘΔϩδοΫ͕ू͞ΕΔ w ঢ়ଶͷՃ࣌ʹطଘͷ࣮ʹରͯ͠ཏੑΛڧ੍Ͱ͖Δ w ঢ়ଶʹର໊ͯ͠લ͕ͭ͘
ϩδοΫ͕ू͞ΕΔ // ਏ͍ྫ class HogeEntity { private state: HogeState; constructor(
private id: HogeId, private name: string, private enable: boolean, private body: string, private selected: boolean, private focused: boolean, ) {} toHoge() { // ঢ়ଶͷมߋ͕෦ʹӅṭ͞Ε͓ͯΓɺςετ͕͍͠ } }
ϩδοΫ͕ू͞ΕΔ // ָͳྫ type MessageStateLiterals = "sending" | "loading" /…/;
class MessageState { private state: MessageStateLiterals; constructor( sending: boolean, loading: boolean, editing: boolean, deleted: boolean, ) { // ݅ʹԠͯ͡this.stateMessageStateLiteralsͷ͍ͣΕ͔Λೖ } match<R>(matcher: { [key in MessageStateLiterals]: () => R }): R { return matcher[this.status](); } }
ϩδοΫ͕ू͞ΕΔ // ָͳྫʢςετʣ describe(`MessageState`, () => { const matcher =
{ "sending": () => "sending", // ... }; [ { enable: false, selected: false, focused: false, result: "disabled" }, // શͯͷมͷΈ߹ΘͤΛॻ͘ ].forEach(param => { it(JSON.stringify(param), () => { let state = new MessageState(param.enable, param.selected, param.focused); assert(state.match(matcher) === param.result); }); }); });
ঢ়ଶͷՃ࣌ʹطଘͷ࣮ʹରͯ͠ ཏੑΛڧ੍Ͱ͖Δ // matcherʹશͯͷύλʔϯͷkeyΛίϯύΠϥϨϕϧͰڧ੍ match<R>(matcher: { [key in TypeLiterals]: ()
=> R }): R { return matcher[this.status](); }
ঢ়ଶͷՃ࣌ʹطଘͷ࣮ʹରͯ͠ ཏੑΛڧ੍Ͱ͖Δ // key͕ෆ͍ͯ͠Δ߹ɺίϯύΠϧ͕௨Βͳ͍ɻ type MessageStateLiterals = "sending" | "loading"
// …; class MessageState { // ... match<R>(matcher: { [key in MessageStateLiterals]: () => R }): R { return matcher[this.status](); } } const state = new MessageState(/.../); state.match({ "sending": () => true, // Compile error! });
ঢ়ଶʹର໊ͯ͠લ͕ͭ͘ // ਏ͍ྫ class Message { constructor( private sending: boolean,
private editing: boolean, private deleted: boolean, ) {} canEdit(): boolean { // canEditʮฤू͕Մೳʯͱ͍͏݁ՌΛฦ͍ͯ͠Δ͚ͩͰɺ // ͦͷ࣌ͷMessageͷঢ়ଶද͍ͯ͠ͳ͍ɻ } }
DBO&EJU͓ͦΒ͘ʮฤूՄೳͳঢ়ଶʯͱݴ͍͍ͬͯ ͕ɺࢀর͢Δม͕૿͍͑ͯ͘ͱʮಛఆͷঢ়ଶͱͲ͏ ͍͏มͷΈ߹Θͤͳͷ͔ʁʯͷѲ͕͘͠ͳͬͯ ͘Δɻ ʮಛఆͷ݅ʹର͢ΔมͷΈ߹Θͤʯ͕ෆ໌ͳঢ়ଶ ͕ଓ͘ͱɺͦͷ͏ͪʮݱঢ়ͷมͷΈ߹ΘͤΛಛఆͷ ݅ͱ͢ΔʯΑ͏ʹͳΓɺ࣮͕༷Խ͢Δɻ ʢ͔͜͠ΕϦϑΝΫλϦϯάʹϦεΫΛ͍ɺ*%& ͷαϙʔτ͕͋ͬͯਖ਼֬ͳमਖ਼͕ࠔʣ ࣄલʹঢ়ଶΛΓग़͠ɺ໌֬ͳ໊લΛ͚ͭΔ͜ͱͰ࣮
ͷ༷ԽΛࢭ͠ɺमਖ਼ͷ༨Λ͢͜ͱ͕Ͱ͖Δɻ
Ͳ͏͍ͬͨ߹ʹ͏ ͷ͔
Ͳ͏͍ͬͨ߹ʹ͏ͷ͔ w 7BMVF0CKFDUQBUUFSOͷҰ෦ͱͯ͠ w ͦΕͧΕͷ݅ʹ໊ؔͯ͠લ͕ͭ͘ ʢϢϏΩλεݴޠʣ
ࠜຊతʹղܾ͍ͨ͠ Կ͔ʁ
ղܾ͍ͨ͠ w ਖ਼͘͠ྨ͢Δ w ਖ਼໋໊͘͢͠Δ
ʮ݅ذͷ݁Ռͱͯ͠ͷྨʯͰͳ͘ɺ༗ݶݸͷ ྨͷҰͭͱͯ͠ॴଐΛׂΓͯΔɻ ʮૹ৴தϑϥάͱฤूࡁΈϑϥά͕Φϯͷϝοηʔδʯ Ͱͳ͘ɺʮ্ॻ͖ૹ৴தϝοηʔδʯͱͯ͠ڍಈΛׂ ΓͯΔɻ ʮ݅ذͷ݁ՌͷҰ෦ʯͰͳ͘ɺذͷ݁Ռʹର ໊ͯ͠લΛ͚ͭΔɻ ʮૹ৴ऀ͕ۭͰຊจ͕͋Δ߹݅ذ͢ΔʯͷͰͳ ͘ɺʮૹ৴ऀ͕ۭͰຊจ͕͋Δ߹γεςϜϝοηʔδ ͱ໋໊ͯ͢͠Δʯ͜ͱͰɺҎޙʮγεςϜϝοηʔ
δʯʹରͯ͠ॲཧΛߦ͏
࣮ͷ؆ུԽ
ҎԼͷΑ͏ͳDMBTTΛఆٛ͢Δ͜ͱ Ͱ࣮Λ؆ུԽͰ͖Δ type BaseTypeLiterals<L extends string, R> = { [key
in L]: () => R } abstract class BaseType<TypeLiterals extends string> { constructor(protected value: TypeLiterals) {} getValue(): TypeLiterals { return this.value; } equals(type: TypeLiterals): boolean { return this.getValue() === type; } equalType<T extends this>(target: T): boolean { return this.getValue() === target.getValue(); } match<R>(matcher: BaseTypeLiterals<TypeLiterals, R>): R { return matcher[this.getValue()](); } }
ҎԼͷΑ͏ͳDMBTTΛఆٛ͢Δ͜ͱ Ͱ࣮Λ؆ུԽͰ͖Δ class MessageState extends BaseType<"sending" | /.../ > {
constructor( sending: boolean, loading: boolean, /.../ ) { if (sending) { return super("sending"); } // ඞཁͳذΛՃ } }
2"
2" w 2ɿ༷ύλʔϯʢ4QFDJpDBUJPOύλʔϯʣͰʁ w "ɿ:FTɻͨͩɺ5ZQF4DSJQUͰTFBMFEम০ࢠΛ࠶ݱͰ͖ͨͷίʔυΛॻ্͘Ͱศ རͩͬͨ ʢ4DBMBͬͯΔਓʹͨΓલͰʣ w 2ɿ+BWBͷ&OVNͰʁ w
"ɿ+BWBͷ&OVNͰTXJDIͷཏੑΛڧ੍Ͱ͖ͳ͍ͷͰेͰͳ͍ͱ͍͏ཧղ ʢͪͳΈʹ5ZQF4DSJQUͷFOVNશ͘ʹཱͨͳ͍ͱ͍͏ͷਃ͠ఴ͓͖͑ͯ·͢ʣ w 2ɿ4XJGUͷ&OVNͰʁ w "ɿ:FTɻ<4XJGU8BTNDPNQJMF4XJGUUP8FC"TTFNCMZ> IUUQT TXJGUXBTNPSH
͓ΘΓ