Vuexに型を付けるパターンを調べた #gotandajs

Vuexに型を付けるパターンを調べた #gotandajs

E1dbe585427fa87cbfb0f4dbcebc3b2f?s=128

mizuki_r

July 26, 2019
Tweet

Transcript

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

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

    Recruitment, etc…
  3. 今日のお話

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

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

  6. Vuexの型付けで悩み…

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

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

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

    • 予めご了承ください
  10. 背景

  11. 税理士ドットコム • 日本最大級の税理士/税務ポータルサイト • 税理士紹介、Q&A、ニュースなど • 2016年〜 • 私 +

    業務委託エンジニアx5
  12. 管理画面 with Vue • もともとPHP Yii Frameworkが内包するUIモ ジュール+ jQuery を使っていた

    • 長年の運用と範囲の拡大にインタラクションが不 足 • システムの一部でVueを導入(半年ほど前) • Form操作の複雑化に伴い、型が欲しくなる←イマココ
  13. 型に対する期待 • データ構造の補完 • データ構造のドキュメント化 • 値の受け渡しミスの抑止 • メンバーの学習

  14. 悩みどころ • Vueの中でのレールが無い • サードパーティを使う必要がある • Vue+Vuex+VueRouterの範囲なら公式のライブラリ使いたい • dispatch, getters,

    commitで型が落ちる • サードパーティ(ry • これまでの「Vueを使う」インタラクションから離れる必要がある • Vuexのパターンがライブラリに引っ張られる • VuexのモジュールをVueに露出させないといけない
  15. 方針

  16. 前提 • Vueを使う • メンバーの知識的、学習補助のコスパ的に • 段階的にTypeScriptを導入する • 全体をまとめて、はリスクとコスト的にやらない •

    Multiple Page Application + Single Page Application • システムの一部をSPAにする
  17. 方針 • Vue - Vuex 間で型情報を維持する • Vuexで構築するデータ構造には固く型を付 けられる •

    将来的にはAPIの構造が変わったらコンパイ ルで気付ける構造にしたい(遠い未来)
  18. Vuex + TypeScriptの パターンを調べた

  19. パターン • vuex + vuex-class • vuex-type-helper + vuex-class •

    vuex-module-decorator • vuex-smart-module
  20. vuex + vuex-class

  21. vuex + vuex-class • vuexに搭載されている型 + vuex-class を使う • 標準にもっとも近い形で書ける

    • dispatchとgetterをvuex-classが隠蔽する • Store内部でのdispatch, getterの型が抜ける • Component側のインタラクションが若干変わる
  22. 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<RootState, RootState> = { getNotes(state) { return () => (state.notes ? state.notes.rows : []) } } const mutations: MutationTree<RootState> = {} const actions: ActionTree<RootState, RootState> = { 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 })
  23. vuex-type-helper

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

  25. 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*ETUBUFSPXT<TUBUFSPXTMFOHUI>JE 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^  ^ ^
  26. vuex-module-decorator

  27. vuex-module-decorator • Vuexのモジュール一つのクラスとしてみなす • VuexModuleクラスを継承してデコレータで mutation, actionを定義する • vue-property-decratorに感触的には近い •

    Componentからはモジュールを直接呼び出す ことで型抜けを防ぐ
  28. 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*EUIJTSPXT<UIJTSPXTMFOHUI>JE 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 ^ ^
  29. vuex-smart-module

  30. vuex-smart-module • state, getter, mutation, actionを継承してクラ ス化してModuleに集約する • ComponentからはModuleを呼び出す •

    Vuexの機能単位で分割できる部分を残しているので 既存構造にも適応させやすい • Contextの概念があり、ネストしたModuleへの dispatch, getterが呼び出せる
  31. 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*EUIJTTUBUFSPXT<UIJTTUBUFSPXTMFOHUI>JE 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 ^ 
  32. まとめ

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

  34. Vuex-Typeパターン • Vuexに対して型を付与パターン(既存のVuexと相 性が良い) • vuex • vuex-type-helper, etc •

    モジュール化パターン(新しくモジュール構成を考 える) • vuex-module-decorator, • vuex-smart-module, etc
  35. 何を採用するか? • Vue-Vuexの間でどういうやり取りするかが 大きく関わるので全体を考える必要がある • アプリがライブラリに依存する • サードパーティなので、アップデートの追 従とかも考えたほうがいい •

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

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