好久沒寫技術文章
不對,好像從來沒寫過
不過先上圖,不然一定沒人看
第二張可以拿來訓練恥ㄌ…當桌布

下面要開始認真囉,被腿釣進來的可以先行離席了
離席後可去 P 網領差分

那,這次主要就是介紹幾個 vuex + typescript 的套件
你是否曾經因為沒有型別而感到不安、焦慮、甚至顫抖

最近接觸新專案,全是 js
而且專案都還蠻大的,在想好像該導入 ts 會比較容易維護
vue 的部分是還好,現在 vue 對 ts 的支援其實還不錯
比較大的問題是 vuex
dispatch, commit 沒有提示、型別檢查,是要成為通靈王嗎
所以找了幾套讓 vuex 可以有型別檢查的套件,需求是
1. component 中使用 state, getters, mutations, actions 要有型別
2. component 中不需 import 型別
3. 可以透過 this.$myStore.xxx 直接呼叫 (有的話最好)
最後挑出了這幾套

1. vuex-simple
2. vuex-tstore
3. vuex-ts-enhance
4. vuex-ts-action

下面附上各套使用範例

vuex-simple


github: https://github.com/sascha245/vuex-simple
npm: https://www.npmjs.com/package/vuex-simple

最推這套,寫起來最簡潔
module 就當一般 class 寫就好
新專案或 store 架構還不大推薦就用這套
缺點
module 非 vuex 原生寫法
還有就是因為寫在同一個 class 的關係
mutation, action 不能同名

example

import { Mutation, State, Action, createVuexStore, useStore, Module } from 'vuex-simple';

class UserModule {
@State()
public name: string = '';

@Mutation()
public updateName(name: string) {
this.name = name;
}

@Action()
public async patchName(payload: { name: string }) {
this.updateName(payload.name);
return 'name';
}
}

class RootModule {
@Module()
public user = new UserModule();
}

export const store = createVuexStore(new RootModule());
export const $tstore: RootModule = useStore(store);

// bind $tstore to vue instance
// state: this.$tstore.user.name
// mutation: this.$tstore.user.updateName()
// action: this.$tstore.user.patchName()



vuex-tstore


github: https://github.com/stevethedev/vuex-tstore
npm: https://www.npmjs.com/package/vuex-tstore

跟 vuex-simple 其實蠻類似的
不過可以用 vuex 原生的寫法
如果想要型別又沒辦法大改寫法可以先用這套頂著
缺點
相較 vuex-simple,呼叫方法時寫起來有點冗長
在 action 呼叫 action/mutation 時沒有型別

example

import TStore from 'vuex-tstore';

const userState = {
name: '',
};

const userModule = {
state: userState,
mutations: {
updateName(state: typeof userState, name: string) {
state.name = name;
},
},
actions: {
async patchName(ctx: any, payload: { name: string }) {
ctx.commit('updateName', payload.name);
return 'name';
},
},
};

const rootModule = {
modules: {
user: userModule,
},
};

export const $tstore = new TStore.Store(rootModule);
export const store = $tstore.store;

// bind $tstore to vue instance
// state: this.$tstore.modules.user.state.name
// mutation: this.$tstore.modules.user.mutations.updateName()
// action: this.$tstore.modules.user.actions.patchName()


vuex-ts-enhance

github: https://github.com/zWingz/vuex-ts-enhance#readme
npm: https://www.npmjs.com/package/vuex-ts-enhance

珍惜下班時間,遠離 store mapping
這是針對 store mapping 提供提示與型別檢查
相信大家都踩過 mapXXX 的雷
在前公司我們還限制不准用
原本想說有 vuex-tstore 應該就夠了
但發現現在的專案滿滿 mapXXX,崩潰潰
找到這套也蠻意外的
不過它提供很有限
缺點
只能用在兩層 module 的 store,不能再多
在 action 呼叫 action/mutation 時沒有型別
example

import { EnhanceStore } from 'vuex-ts-enhance';

const userState = {
name: '',
};

const userModule = {
state: userState,
mutations: {
updateName(state: typeof userState, name: string) {
state.name = name;
},
},
actions: {
async patchName(ctx: any, payload: { name: string }) {
ctx.commit('updateName', payload.name);
return 'name';
},
},
};

const rootModule = {
modules: {
user: userModule,
},
};

export const {
store,
mapActions,
mapMutations,
mapState,
} = new EnhanceStore(rootModule);

// import { mapAction, mapMutations, mapState } from {store path};
// ...mapActions('user', ['patchName'])
// ...mapMutations('user', ['updateName'])
// it will suggest you and give type checking, but it only support the 1-depth submodules.


vuex-ts-action


github: https://github.com/natsusola/vuex-ts-action#readme
npm: https://www.npmjs.com/package/vuex-ts-action

自肥
這套是我寫的,不過也只是做個 interface 而已
如上面兩套提到的缺點,action 呼叫 action/mutation 時沒有型別
所以這個就是讓你在 action 呼叫 action/mutation 時有提示 & 型別
缺點
寫起來有點麻煩,要一直加型別
因為定義的關係不能使用 ActionTree/MutationTree 那種一次全定義的
或有人可以跟我說怎麼寫

example

import Vuex from 'vuex';
import { TActionContext } from 'vuex-ts-action';

const state = {
name: '',
};
type state = typeof state;

const mutations = {
updateName(state: state, name: string) {
state.name = name;
},
};

const actions = {
async patchName(ctx: TActionCtx, payload: { name: string }) {
ctx.commit('updateName', payload.name);
return 'name';
},
};
type TActionCtx = TActionContext<typeof mutations, typeof actions>

const module = {
state,
mutations,
actions,
};

export const store = new Vuex.Store(module);


總結
這次找的過程其實也蠻有趣的
在找到 vuex-tstore, vuex-ts-enhance 時
其實它們都些不完善的地方
vuex-tstore 原本不支援提示 submodule 的 state
vuex-ts-enhance 原本不支援 mapMutation 和回傳 mutation/action 型別
因為要用到,所以我就抓下來發 PR 給作者
為了改那些東西也讓我對 ts interface 有更進一步的認識
回到套件
推薦 vuex-simple > vuex-tstore > vuex-ts-enhance
後面兩個可以配合 vuex-ts-action 使用
除非既有專案的 module 非常大了
不然還是 vuex-simple 寫起來最舒服
如果以上套件對你有幫助的話
可以在 github 上給作者星星喔

One Response so far.

Leave a Reply