Slide 1

Slide 1 text

5ZQF4DSJQUͰ5ZQF.BUDIత ͳ͜ͱΛ͢Δ࿩ ͑͢ͳΈνϟϯεॵؾ෷͍ !LZP@BHP

Slide 2

Slide 2 text

݁࿦

Slide 3

Slide 3 text

TFBMFEDMBTT PSUSBJU Λ࢖͍·͠ΐ͏ 4DBMBͷ

Slide 4

Slide 4 text

ຊ୊

Slide 5

Slide 5 text

͜Ε͸Կʁ

Slide 6

Slide 6 text

5ZQF4DSJQUͷ4USJOH-JUFSBM5ZQFTΛ࢖ͬͨ ঢ়ଶͷ؅ཧ$IBUXPSL$SFBUPST/PUF ͷվม൛Ͱ͢ɻ

Slide 7

Slide 7 text

ԿΛղܾ͍ͨ͠ͷ͔

Slide 8

Slide 8 text

ෳࡶͳঢ়ଶɺ৚݅෼ذΛ༰ қʹѻ͑ΔΑ͏ʹ͍ͨ͠ ʢෳࡶͳঢ়ଶɿCPPMFBOͭͱ͔Ͱ؅ཧͯ͠ΔΑ͏ͳͷʣ

Slide 9

Slide 9 text

۩ମతʹ͸

Slide 10

Slide 10 text

// ਏ͍ྫ class Message { constructor( private sending: boolean, private editing: boolean, private deleted: boolean, ) {} canEdit(): boolean { if ( !this.sending && !this.deleted ) { return false; } return true; } }

Slide 11

Slide 11 text

͞Βʹ

Slide 12

Slide 12 text

// ΋ͬͱਏ͍ྫ 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; } }

Slide 13

Slide 13 text

Կ͕໰୊ͳͷ͔

Slide 14

Slide 14 text

໰୊఺ w ঢ়ଶͷ૊Έ߹Θ͕ͤ৚݅෼ذΛΈͳ͍ͱ൑அͰ͖ͳ͍ w ৚݅෼ذͷJG͕ෳࡶ w ม਺͕௥Ճ͞Εͨ৔߹ͷ໢ཏੑͷอূ͕೉͍͠

Slide 15

Slide 15 text

// ਏ͍ྫ 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; } }

Slide 16

Slide 16 text

DMBTTNFUIPE಺Ͱ௚઀৚݅෼ذΛߦ͏ͱɺʮಛఆͷঢ় گԼͰDMBTT͕Ͳ͏͍͏ঢ়ଶʹͳΔ͔ʁʯͷ൑அ͕೉͘͠ ͳΔɻ ৚݅෼ذ͸ͦͷঢ়ଶʹ໊લΛ͚ͭͳ͍ͨΊɺʮ৚݅෼ذ ʹҰக͢Δͷ͸Ͳ͏͍͏ঢ়ଶ͔ʁʯʹର͢Δղऍ͕ᐆດ ʹͳΔɻ ʢ͜ͷ৔߹ɺDBO&EJU͸ʮฤूՄೳͳঢ়ଶʯͰҰக͢Δ ͱࢥ͏͚Ͳʣ

Slide 17

Slide 17 text

// ֎෦͔Βݟͯಉ͡ঢ়ଶ͔ʁ const message = new Message(/.../); const getEditableMessage = () => { return message.canEdit() ? "मਖ਼Ͱ͖ΔΑʂ" : "मਖ਼ Ͱ͖ͳ͍Αʂ"; } const showEditableIcon = () => { return message.canEdit(); }

Slide 18

Slide 18 text

ྫ͑͹ɺ৽͘͠ʮJT4FDSFUʯͱ͍͏ม਺Λ௥Ճ͠ ͨ৔߹ɺDBO&EJUʹӨڹ͢ΔͩΖ͏͔ʁ ·ͨɺӨڹ͢Δͱͯ͠ɺDBO&EJUΛݺͼग़͍ͯ͠ Δଆ΋ಉ͡૝ఆͩΖ͏͔ʁ

Slide 19

Slide 19 text

Ͳ͏ղܾ͢Δͷ͔

Slide 20

Slide 20 text

ঢ়ଶΛDMBTTԽ͢Δ

Slide 21

Slide 21 text

// ָͳྫ type MessageStateLiterals = "sending" | "loading" | "editing" | "deleted"; class MessageState { private state: MessageStateLiterals; constructor( sending: boolean, loading: boolean, editing: boolean, deleted: boolean, ) { // ৚݅ʹԠͯ͡this.state΁MessageStateLiteralsͷ͍ͣΕ ͔Λ୅ೖ } match(matcher: { [key in MessageStateLiterals]: () => R }): R { return matcher[this.status](); } }

Slide 22

Slide 22 text

࢖͍ํ

Slide 23

Slide 23 text

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, }); } }

Slide 24

Slide 24 text

ར఺

Slide 25

Slide 25 text

ར఺ w ঢ়ଶͷ൑அʹؔΘΔϩδοΫ͕ू໿͞ΕΔ w ঢ়ଶͷ௥Ճ࣌ʹطଘͷ࣮૷ʹରͯ͠໢ཏੑΛڧ੍Ͱ͖Δ w ঢ়ଶʹର໊ͯ͠લ͕ͭ͘

Slide 26

Slide 26 text

ϩδοΫ͕ू໿͞ΕΔ // ਏ͍ྫ 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() { // ঢ়ଶͷมߋ͕಺෦ʹӅṭ͞Ε͓ͯΓɺςετ͕೉͍͠ } }

Slide 27

Slide 27 text

ϩδοΫ͕ू໿͞ΕΔ // ָͳྫ type MessageStateLiterals = "sending" | "loading" /…/; class MessageState { private state: MessageStateLiterals; constructor( sending: boolean, loading: boolean, editing: boolean, deleted: boolean, ) { // ৚݅ʹԠͯ͡this.state΁MessageStateLiteralsͷ͍ͣΕ͔Λ୅ೖ } match(matcher: { [key in MessageStateLiterals]: () => R }): R { return matcher[this.status](); } }

Slide 28

Slide 28 text

ϩδοΫ͕ू໿͞ΕΔ // ָͳྫʢςετʣ 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); }); }); });

Slide 29

Slide 29 text

ঢ়ଶͷ௥Ճ࣌ʹطଘͷ࣮૷ʹରͯ͠ ໢ཏੑΛڧ੍Ͱ͖Δ // matcherʹશͯͷύλʔϯͷkeyΛίϯύΠϥϨϕϧͰڧ੍ match(matcher: { [key in TypeLiterals]: () => R }): R { return matcher[this.status](); }

Slide 30

Slide 30 text

ঢ়ଶͷ௥Ճ࣌ʹطଘͷ࣮૷ʹରͯ͠ ໢ཏੑΛڧ੍Ͱ͖Δ // key͕ෆ଍͍ͯ͠Δ৔߹ɺίϯύΠϧ͕௨Βͳ͍ɻ type MessageStateLiterals = "sending" | "loading" // …; class MessageState { // ... match(matcher: { [key in MessageStateLiterals]: () => R }): R { return matcher[this.status](); } } const state = new MessageState(/.../); state.match({ "sending": () => true, // Compile error! });

Slide 31

Slide 31 text

ঢ়ଶʹର໊ͯ͠લ͕ͭ͘ // ਏ͍ྫ class Message { constructor( private sending: boolean, private editing: boolean, private deleted: boolean, ) {} canEdit(): boolean { // canEdit͸ʮฤू͕Մೳʯͱ͍͏݁ՌΛฦ͍ͯ͠Δ͚ͩͰɺ // ͦͷ࣌ͷMessageͷঢ়ଶ͸ද͍ͯ͠ͳ͍ɻ } }

Slide 32

Slide 32 text

DBO&EJU͸͓ͦΒ͘ʮฤूՄೳͳঢ়ଶʯͱݴ͍͍ͬͯ ͕ɺࢀর͢Δม਺͕૿͍͑ͯ͘ͱʮಛఆͷঢ়ଶͱ͸Ͳ͏ ͍͏ม਺ͷ૊Έ߹Θͤͳͷ͔ʁʯͷ೺Ѳ͕೉͘͠ͳͬͯ ͘Δɻ ʮಛఆͷ৚݅ʹର͢Δม਺ͷ૊Έ߹Θͤʯ͕ෆ໌ͳঢ়ଶ ͕ଓ͘ͱɺͦͷ͏ͪʮݱঢ়ͷม਺ͷ૊Έ߹ΘͤΛಛఆͷ ৚݅ͱ͢ΔʯΑ͏ʹͳΓɺ࣮૷͕࢓༷Խ͢Δɻ
 ʢ͔͠΋͜Ε͸ϦϑΝΫλϦϯάʹϦεΫΛ൐͍ɺ*%& ౳ͷαϙʔτ͕͋ͬͯ΋ਖ਼֬ͳमਖ਼͕ࠔ೉ʣ ࣄલʹঢ়ଶΛ੾Γग़͠ɺ໌֬ͳ໊લΛ͚ͭΔ͜ͱͰ࣮૷ ͷ࢓༷ԽΛ཈ࢭ͠ɺमਖ਼ͷ༨஍Λ࢒͢͜ͱ͕Ͱ͖Δɻ

Slide 33

Slide 33 text

Ͳ͏͍ͬͨ৔߹ʹ࢖͏ ͷ͔

Slide 34

Slide 34 text

Ͳ͏͍ͬͨ৔߹ʹ࢖͏ͷ͔ w 7BMVF0CKFDUQBUUFSOͷҰ෦ͱͯ͠ w ͦΕͧΕͷ৚݅ʹ໊ؔͯ͠લ͕ͭ͘
 ʢϢϏΩλεݴޠʣ

Slide 35

Slide 35 text

ࠜຊతʹղܾ͍ͨ͠໰ ୊͸Կ͔ʁ

Slide 36

Slide 36 text

ղܾ͍ͨ͠໰୊ w ਖ਼͘͠෼ྨ͢Δ w ਖ਼໋໊͘͢͠Δ

Slide 37

Slide 37 text

ʮ৚݅෼ذͷ݁Ռͱͯ͠ͷ෼ྨʯͰ͸ͳ͘ɺ༗ݶݸͷ෼ ྨͷҰͭͱͯ͠ॴଐΛׂΓ౰ͯΔɻ ʮૹ৴தϑϥάͱฤूࡁΈϑϥά͕Φϯͷϝοηʔδʯ Ͱ͸ͳ͘ɺʮ্ॻ͖ૹ৴தϝοηʔδʯͱͯ͠ڍಈΛׂ Γ౰ͯΔɻ ʮ৚݅෼ذͷ݁ՌͷҰ෦෼ʯͰ͸ͳ͘ɺ෼ذͷ݁Ռʹର ໊ͯ͠લΛ͚ͭΔɻ ʮૹ৴ऀ͕ۭͰຊจ͕͋Δ৔߹৚݅෼ذ͢ΔʯͷͰ͸ͳ ͘ɺʮૹ৴ऀ͕ۭͰຊจ͕͋Δ৔߹γεςϜϝοηʔδ ͱ໋໊ͯ͢͠Δʯ͜ͱͰɺҎޙ͸ʮγεςϜϝοηʔ δʯʹରͯ͠ॲཧΛߦ͏

Slide 38

Slide 38 text

࣮૷ͷ؆ུԽ

Slide 39

Slide 39 text

ҎԼͷΑ͏ͳDMBTTΛఆٛ͢Δ͜ͱ Ͱ࣮૷Λ؆ུԽͰ͖Δ type BaseTypeLiterals = { [key in L]: () => R } abstract class BaseType { constructor(protected value: TypeLiterals) {} getValue(): TypeLiterals { return this.value; } equals(type: TypeLiterals): boolean { return this.getValue() === type; } equalType(target: T): boolean { return this.getValue() === target.getValue(); } match(matcher: BaseTypeLiterals): R { return matcher[this.getValue()](); } }

Slide 40

Slide 40 text

ҎԼͷΑ͏ͳDMBTTΛఆٛ͢Δ͜ͱ Ͱ࣮૷Λ؆ུԽͰ͖Δ class MessageState extends BaseType<"sending" | /.../ > { constructor( sending: boolean, loading: boolean, /.../ ) { if (sending) { return super("sending"); } // ඞཁͳ෼ذΛ௥Ճ } }

Slide 41

Slide 41 text

2"

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

͓ΘΓ