Slide 1

Slide 1 text

Vuexに型を付けるパターン を調べた 2019/07/26 Gotanda.js #12 @mizuki_r

Slide 2

Slide 2 text

@mizuki_r 弁護士ドットコム株式会社 税理士ドットコム事業部/開発チーム チームマネージャー 2 自己紹介 PHP, Vue, Nuxt, Management, Recruitment, etc…

Slide 3

Slide 3 text

今日のお話

Slide 4

Slide 4 text

運用中のサービスに Vue+TypeScriptを導入した話

Slide 5

Slide 5 text

ーーを、しようと思ったが…

Slide 6

Slide 6 text

Vuexの型付けで悩み…

Slide 7

Slide 7 text

今日までに 結論が出せなかった…

Slide 8

Slide 8 text

ーーので、 Vuexの型付を調べた話 をします

Slide 9

Slide 9 text

免責事項 • 個人の見解に基づく発表であり組織・団体の主張する意見 ではありません • 業務の片手間でググった範囲なので最新の情報ではない可 能性があります • 時間の都合上、各ライブラリの型定義までしっかり読み込 んできたわけではないので間違いがあるかもしれません • 予めご了承ください

Slide 10

Slide 10 text

背景

Slide 11

Slide 11 text

税理士ドットコム • 日本最大級の税理士/税務ポータルサイト • 税理士紹介、Q&A、ニュースなど • 2016年〜 • 私 + 業務委託エンジニアx5

Slide 12

Slide 12 text

管理画面 with Vue • もともとPHP Yii Frameworkが内包するUIモ ジュール+ jQuery を使っていた • 長年の運用と範囲の拡大にインタラクションが不 足 • システムの一部でVueを導入(半年ほど前) • Form操作の複雑化に伴い、型が欲しくなる←イマココ

Slide 13

Slide 13 text

型に対する期待 • データ構造の補完 • データ構造のドキュメント化 • 値の受け渡しミスの抑止 • メンバーの学習

Slide 14

Slide 14 text

悩みどころ • Vueの中でのレールが無い • サードパーティを使う必要がある • Vue+Vuex+VueRouterの範囲なら公式のライブラリ使いたい • dispatch, getters, commitで型が落ちる • サードパーティ(ry • これまでの「Vueを使う」インタラクションから離れる必要がある • Vuexのパターンがライブラリに引っ張られる • VuexのモジュールをVueに露出させないといけない

Slide 15

Slide 15 text

方針

Slide 16

Slide 16 text

前提 • Vueを使う • メンバーの知識的、学習補助のコスパ的に • 段階的にTypeScriptを導入する • 全体をまとめて、はリスクとコスト的にやらない • Multiple Page Application + Single Page Application • システムの一部をSPAにする

Slide 17

Slide 17 text

方針 • Vue - Vuex 間で型情報を維持する • Vuexで構築するデータ構造には固く型を付 けられる • 将来的にはAPIの構造が変わったらコンパイ ルで気付ける構造にしたい(遠い未来)

Slide 18

Slide 18 text

Vuex + TypeScriptの パターンを調べた

Slide 19

Slide 19 text

パターン • vuex + vuex-class • vuex-type-helper + vuex-class • vuex-module-decorator • vuex-smart-module

Slide 20

Slide 20 text

vuex + vuex-class

Slide 21

Slide 21 text

vuex + vuex-class • vuexに搭載されている型 + vuex-class を使う • 標準にもっとも近い形で書ける • dispatchとgetterをvuex-classが隠蔽する • Store内部でのdispatch, getterの型が抜ける • Component側のインタラクションが若干変わる

Slide 22

Slide 22 text

import Vue from 'vue' import Vuex, { GetterTree, MutationTree, ActionTree } from 'vuex' import { RootState, NoteForm } from './types' import * as notes from './notes' Vue.use(Vuex) const state: RootState = {} const getters: GetterTree = { getNotes(state) { return () => (state.notes ? state.notes.rows : []) } } const mutations: MutationTree = {} const actions: ActionTree = { async viewIndex(ctx) { ctx.dispatch('notes/fetch') }, async addNote(ctx, form: NoteForm) { ctx.dispatch('notes/add', form) } } const modules = { notes } export default new Vuex.Store({ state, mutations, actions, modules })

Slide 23

Slide 23 text

vuex-type-helper

Slide 24

Slide 24 text

vuex-type-helper • vuexの型ではなくvuex-type-helperを使う • interfaceに基づいて片付けができる • dispatchとgetterにinterfaceを適応できる • ネストモジュールに対してはすべてのaction とpayloadをinterfaceに記載する必要がある

Slide 25

Slide 25 text

JNQPSU\%FGJOF(FUUFST %FGJOF.VUBUJPOT %FGJOF"DUJPOT^GSPNWVFYUZQFIFMQFS FYQPSUDPOTUOBNFTQBDFEUSVF FYQPSUDPOTUTUBUF/PUFT4UBUF\SPXT<>^ FYQPSUDPOTUHFUUFST%FGJOF(FUUFST/PUFT(FUUFST /PUFT4UBUF 3PPU4UBUF\ SPXT TUBUF \ SFUVSO TUBUFSPXT ^ ^ FYQPSUDPOTUNVUBUJPOT%FGJOF.VUBUJPOT/PUFT.VUBUJPOT /PUFT4UBUF\ '&5$)@3&40-7& TUBUF \SPXT^ \ TUBUFSPXTSPXT ^ "%%@3&40-7& TUBUF \GPSN^ \ DPOTUMBTU*ETUBUFSPXTJE DPOTUOPUF/PUF&OUJUZ\ JEMBTU*E DPOUFOUGPSNDPOUFOU DSFBUFEOFX%BUF ^ TUBUFSPXTQVTI OPUF ^ ^ FYQPSUDPOTUBDUJPOT%FGJOF"DUJPOT /PUFT"DUJPOT /PUFT4UBUF /PUFT.VUBUJPOT 3PPU4UBUF \ BTZODGFUDI DUY \ DPOTUSPXT/PUF&OUJUZ<>< \JE DPOUFOUUFTU DSFBUFEOFX%BUF ^ > DUYDPNNJU '&5$)@3&40-7& \SPXT^ ^ BTZODBEE DUY \GPSN^ \ DUYDPNNJU "%%@3&40-7& \GPSN^ ^ ^

Slide 26

Slide 26 text

vuex-module-decorator

Slide 27

Slide 27 text

vuex-module-decorator • Vuexのモジュール一つのクラスとしてみなす • VuexModuleクラスを継承してデコレータで mutation, actionを定義する • vue-property-decratorに感触的には近い • Componentからはモジュールを直接呼び出す ことで型抜けを防ぐ

Slide 28

Slide 28 text

JNQPSU\/PUF&OUJUZ /PUF'PSN^GSPNUZQFT JNQPSU\7VFY.PEVMF .VUBUJPO "DUJPO^GSPNWVFYNPEVMFEFDPSBUPST FYQPSUEFGBVMUDMBTT/PUFT.PEVMFFYUFOET7VFY.PEVMF\ SPXT/PUF&OUJUZ<><> !.VUBUJPO '&5$)@3&40-7& SPXT/PUF&OUJUZ<> \ UIJTSPXTSPXT ^ !.VUBUJPO "%%@3&40-7& GPSN/PUF'PSN \ DPOTUMBTU*EUIJTSPXTJE DPOTUOPUF/PUF&OUJUZ\ JEMBTU*E DPOUFOUGPSNDPOUFOU DSFBUFEOFX%BUF ^ UIJTSPXTQVTI OPUF ^ !"DUJPO BTZODGFUDI \ DPOTUSPXT/PUF&OUJUZ<>< \JE DPOUFOUUFTU DSFBUFEOFX%BUF ^ > SFUVSOSPXT ^ !"DUJPO BTZODBEE GPSN/PUF'PSN \ SFUVSOGPSN ^ ^

Slide 29

Slide 29 text

vuex-smart-module

Slide 30

Slide 30 text

vuex-smart-module • state, getter, mutation, actionを継承してクラ ス化してModuleに集約する • ComponentからはModuleを呼び出す • Vuexの機能単位で分割できる部分を残しているので 既存構造にも適応させやすい • Contextの概念があり、ネストしたModuleへの dispatch, getterが呼び出せる

Slide 31

Slide 31 text

JNQPSU\(FUUFST .VUBUJPOT "DUJPOT .PEVMF^GSPNWVFYTNBSUNPEVMF JNQPSU\/PUF&OUJUZ /PUF'PSN^GSPNUZQFT FYQPSUDPOTUOBNFTQBDFEUSVF FYQPSUDMBTT/PUFT4UBUF\ SPXT/PUF&OUJUZ<><> ^ FYQPSUDMBTT/PUFT(FUUFSTFYUFOET(FUUFST/PUFT4UBUF\ SPXT \ SFUVSOUIJTTUBUFSPXT ^ ^ FYQPSUDMBTT/PUFT.VUBUJPOTFYUFOET.VUBUJPOT/PUFT4UBUF\ '&5$)@3&40-7& SPXT/PUF&OUJUZ<> \ UIJTTUBUFSPXTSPXT ^ "%%@3&40-7& GPSN/PUF'PSN \ DPOTUMBTU*EUIJTTUBUFSPXTJE DPOTUOPUF/PUF&OUJUZ\ JEMBTU*E DPOUFOUGPSNDPOUFOU DSFBUFEOFX%BUF ^ UIJTTUBUFSPXTQVTI OPUF ^ ^ FYQPSUDMBTT/PUFT"DUJPOTFYUFOET"DUJPOT /PUFT4UBUF /PUFT(FUUFST /PUFT.VUBUJPOT /PUFT"DUJPOT \ BTZODGFUDI \ DPOTUSPXT/PUF&OUJUZ<>< \JE DPOUFOUUFTU DSFBUFEOFX%BUF ^ > UIJTDPNNJU '&5$)@3&40-7& SPXT ^ BTZODBEE GPSN/PUF'PSN \ UIJTDPNNJU "%%@3&40-7& GPSN ^ ^ FYQPSUEFGBVMUOFX.PEVMF \ TUBUF/PUFT4UBUF HFUUFST/PUFT(FUUFST NVUBUJPOT/PUFT.VUBUJPOT BDUJPOT/PUFT"DUJPOT ^

Slide 32

Slide 32 text

まとめ

Slide 33

Slide 33 text

Vuexに型をつけようと思ったら Vuex-Frameworkの選定になった

Slide 34

Slide 34 text

Vuex-Typeパターン • Vuexに対して型を付与パターン(既存のVuexと相 性が良い) • vuex • vuex-type-helper, etc • モジュール化パターン(新しくモジュール構成を考 える) • vuex-module-decorator, • vuex-smart-module, etc

Slide 35

Slide 35 text

何を採用するか? • Vue-Vuexの間でどういうやり取りするかが 大きく関わるので全体を考える必要がある • アプリがライブラリに依存する • サードパーティなので、アップデートの追 従とかも考えたほうがいい • Vue+TypeScriptは発展途上

Slide 36

Slide 36 text

まとめ • Vuexで片付けするパターンを紹介しました • まだVuexの型は方言が多い • 「ゆるく書ける」Vueの良さとどう同居していくか模 索している • みなさんの意見を聞かせてください

Slide 37

Slide 37 text

ご清聴ありがとうございました