vuexのtsに対するサポートは弱すぎますか?vuexがtypescriptをよりよくサポートするソリューション

17617 ワード

vuexがtypescriptをよりよくサポートするソリューション
従来のvuex符号化が面倒なのはstate、getters、mutation、dispatchが呼び出し時にエディタのスマートヒントを得ることができず、ファイルを切り替えて検索しなければならないことです.typescriptを使えばこの問題は解決できると思っていたが、vuexが公式に提供しているtypesはそれほど強くないことに気づいた...
しばらくいろいろな解決策を探していたら、このような問題やそのような問題(タイプは繰り返し定義が必要で、侵入が深刻で、元の書き方とは全く異なる)があると思っていたので、自分でこのような解決策を書きました.typescriptを得たスマートヒントの下で、いろいろなtypeやinterfaceを繰り返し書く必要はありません.vuexの元の書き方と一致し、ビジネスコードへの侵入は極めて小さいです.
demoプロジェクトはvue-cli 3によって生成され、IDEはVSCDEである.
効果の表示
1. state
stateはすべてのmodule、中の属性、属性のタイプを表示します.
/src/store/modules/auth.ts
const moduleState = {
  token: '',
  tokenExpire: 0,
}

2. getters
getterは値タイプを表示できます
/src/store/modules/auth.ts
const moduleGetters = {
  isLogin(state: State, getters: any, rootState: Store['state'], rootGetters: any) {
    return !!state.token && (!!rootState.user.userId || !!rootState.user.accountId);
  },
};

3. commit
commitには登録されているすべてのmutationと対応するpayloadのタイプが表示され、payloadのタイプが間違っている場合はエラーが表示されます.
/src/store/modules/auth.ts
const mutations = {
  setToken(state: State, payload: State['token']) {
    state.token = payload || '';
  },
  setTokenExpire(state: State, payload: State['tokenExpire']) {
    state.tokenExpire = payload || 0;
  },
};

/src/store/modules/user.ts
const mutations = {
  setAccountId(state: State, payload: State['accountId']) {
    state.accountId = payload || '';
  },
  setUserId(state: State, payload: State['userId']) {
    state.userId = payload || '';
  },
  setUserInfo(state: State, payload: State['info']) {
    state.info = payload || {};
  },
};

/src/store/modules/pageCache.ts
const mutations = {
  setPageToCache(state: State, payload: any) {
    state.pagesName.unshift(payload.pageName);
    setTimeout(() => {
      if (payload.callback) payload.callback();
    }, 0);
  },
  resetPageCache(state: State) {
    state.pagesName = [...cachePages];
  },
};

4. dispatch
commitと似ています
/src/store/modules/auth.ts
const actions = {
  updateAuthData({ commit }: ActionContext, payload: any) {
    commit('setToken', payload.token);
    commit('setTokenExpire', payload.expire);
  },
  cleanAuthData({ commit }: ActionContext) {
    commit('setToken', '');
    commit('setTokenExpire', 0);
  },
};

インプリメンテーションモード
以上のように、このスキームはvuexの元の書き方(少し変化して、this.$storeからthis.$$storeに変更)を保証する上でtypescriptのタイプチェックをサポートしており、それを実現するために、vuexのstoreは初期化時に追加の作業をする必要がありますが、この追加の作業に限られており、後続のmodule(業務)の増加は、完全にvuexの本来の書き方のように各種state、getters、mutation、actionを定義し、typescriptのvuexの各種呼び出しに対するサポートを永遠に獲得する.
1.vuex部分の改造
まず最も基本的なvuexコードを見てみましょう
/store/modules/auth.ts
// ts                any   ,   
const moduleState = {
  token: '',
  tokenExpire: 0,
};

const moduleGetters = {
  isLogin(state, getters, rootState, rootGetters) {
    return !!state.token && (!!rootState.user.userId || !!rootState.user.accountId);
  },
};

const mutations = {
  setToken(state, payload) {
    state.token = payload || '';
  },
  setTokenExpire(state, payload) {
    state.tokenExpire = payload || 0;
  },
};

const actions = {
  updateAuthData({ commit }, payload) {
    commit('setToken', payload.token);
    commit('setTokenExpire', payload.expire);
  },
  cleanAuthData({ commit }) {
    commit('setToken', '');
    commit('setTokenExpire', 0);
  },
};

export default {
  state: moduleState,
  getters: moduleGetters,
  mutations,
  actions,
};

/store/index.ts
import Vue from 'vue';
import Vuex from 'vuex';

import auth from './modules/auth';
import user from './modules/user';
import pageCache from './modules/pageCache';

Vue.use(Vuex);

const store = new Vuex.Store({
  modules: {
    auth,
    user,
    pageCache,
  },
});
export default store;
Magicを追加します
/store/index.ts
import Vue from 'vue';
import Vuex from 'vuex';

import auth from './modules/auth';
import user from './modules/user';
import pageCache from './modules/pageCache';

Vue.use(Vuex);

//   module   state     state       
interface State {
  auth: typeof auth.state;
  user: typeof user.state;
  pageCache: typeof pageCache.state;
}
//   getter       {getterName: getterFuncsReturnType}      
export type ReturnGetters(...args: any) => any }> = {
  [P in keyof T]: ReturnType;
}
//      module   getter       
type GettersFuncs = (
  typeof auth.getters
  & typeof user.getters
  & typeof pageCache.getters
)
//   getter      
type Getters = ReturnGetters
//    mutation     
type CommitFuncs = (
  typeof auth.mutations
  & typeof user.mutations
  & typeof pageCache.mutations
)
//   mutation      payload       commit          
interface Commit {
  (type: T, payload?: Parameters[1]): void;
}
// dispatch       commit
type DispatchFuncs = (
  typeof auth.actions
  & typeof user.actions
  & typeof pageCache.actions
)
interface Dispatch {
  (type: T, payload?: Parameters[1]): Promise;
}

const store = new Vuex.Store({
  modules: {
    auth,
    user,
    pageCache,
  },
});
export default store;

//    ts                    
export const { state } = store;
export const { getters }: { getters: Getters } = store; //    getters    
export const { commit }: { commit: Commit } = store; //    commit    
export const { dispatch }: { dispatch: Dispatch } = store; //    commit    

//      Store     Vue        
export interface Store {
  state: State;
  getters: Getters;
  commit: Commit;
  dispatch: Dispatch;
}

循環参照を避けるために、/src/types/の下に構築する必要があります.d.tsファイルは、各moduleがグローバルなState(rootState、commit、dispatch)に参照できるようにする
/src/types/store.d.ts
import { Store as s } from '../store/index';

export { ReturnGetters } from '../store/index';
export interface Store extends s {}
export interface ActionContext {
  dispatch: Store['dispatch']; //     dispatch,   ts     
  commit: Store['commit']; //     commit,   ts     
  state: S;
  getters: G;
  rootState: Store['state']; //     state,   ts     
  rootGetters: any; //            getter     ,           
}

最後にmoduleを変更します(authのみ)
/src/store/modules/auth.ts
import { ReturnGetters, Store, ActionContext } from '../../types/store';

const moduleState = {
  token: '',
  tokenExpire: 0,
};
type State = typeof moduleState; //    state   

const moduleGetters = {
  isLogin(state: State, getters: any, rootState: Store['state'], rootGetters: any) {
    return !!state.token && (!!rootState.user.userId || !!rootState.user.accountId);
  },
};
type Getters = ReturnGetters<typeof moduleGetters>; //    getter   

const mutations = {
  setToken(state: State, payload: State['token']) {
    state.token = payload || '';
  },
  setTokenExpire(state: State, payload: State['tokenExpire']) {
    state.tokenExpire = payload || 0;
  },
};

const actions = {
  updateAuthData({ commit }: ActionContext, payload: any) {
    commit('setToken', payload.token);
    commit('setTokenExpire', payload.expire);
  },
  cleanAuthData({ commit }: ActionContext) {
    commit('setToken', '');
    commit('setTokenExpire', 0);
  },
};

export default {
  state: moduleState,
  getters: moduleGetters,
  mutations,
  actions,
};

2.vueインスタンス化vuex部分の改造
/src/main.ts
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store, { Store } from './store/index'; 
//    ts             ,         
// import { state, getters, commit, dispatch } from './store/index';

Vue.config.productionTip = false;

const app = new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app');

//        Store       vue     ,      .vue       IDE       
//             Store      ,     vue     $store     ,           $$store        ,      app.$store
Vue.prototype.$$store = app.$store;

declare module 'vue/types/vue' {
  interface Vue {
    $$store: Store;
  }
}


これでvuexのtypescriptサポートの改造が完了しました(ここで/src/store/index.tsはnodejsでスクリプトを書いてすべてのmoduleファイル名を読み込んでmustacheでテンプレートに基づいて生成し、モジュールを追加するたびに1行のコマンドを走って更新することができます)、その後、vuexの元の書き方を楽しく使用してファイルを切り取っていろいろな名前を探すことができず、書き間違えたときにtsはエラーを検証します.母は二度と私がこのような低級な間違いを犯すことを心配する必要はありません~
ps:この案はまだ十分ではないかもしれません(rootGettersタイプは実現していませんなど...)、皆さんの交流と勉強を歓迎します.
ppps:次はこれらのtsタイプのコードをツールライブラリに抽出したいのですが、初歩的に考えてみると少し難しいので、まずdemoの形で共有してみましょう.
demo
アドレス:github
コードを引いてから
yarn install

その後はvueファイルと.tsファイルでvuexを体験してスマートヒントを得るのに便利になりました~
もしあなたに役に立つなら、starをあげてください.
  • 著者:BarneyZhao
  • 著作権は著者の所有である.商業転載は著者に連絡して許可を得てください.非商業転載は出典を明記してください.

  • 転載先:https://juejin.im/post/5d09de7ee51d45108223fc71