Skip to content

Commit

Permalink
feat: vuex Action 完善全局 dispatch
Browse files Browse the repository at this point in the history
  • Loading branch information
imsunhao committed Jul 29, 2019
1 parent c5b9adf commit 7365ccf
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 61 deletions.
70 changes: 45 additions & 25 deletions doc/@types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,19 @@
import { Store } from 'vuex'
import { TMutations as GlobalMutations } from 'src/store/mutations'

/**
* Doc 全局类型
* * typescript namespace
*/
declare namespace Doc {
import { Store } from 'vuex'
import { TMutations as GlobalMutations } from 'src/store/mutations'
import { TActions as GlobalActions } from 'src/store/actions'

type DictOf<T> = { [key: string]: T }

/**
* vuex store
* * typescript namespace
*/
namespace Tstore {
/**
* vuex 创建 工具函数
* * typescript namespace
*/
namespace createUtils {
type ActionDescriptor = [any, any]

/**
* 用于声明 Actions Descriptors
*/
type ActionsOfDescriptors<Context, Descriptor extends DictOf<ActionDescriptor>> = {
[K in keyof Descriptor]: (ctx: Context, payload: Descriptor[K][0]) => Descriptor[K][1]
}

/**
* 用于声明 Mutations
*/
type ModuleMutations<State, PayloadTree> = {
[K in keyof PayloadTree]: (state: State, payload: PayloadTree[K]) => any
}
}

/**
* vuex state
*/
Expand Down Expand Up @@ -94,6 +77,26 @@ declare namespace Doc {
}
}
}

/**
* vuex Action-tree
*/
type Actions = GlobalActions & {
/**
* 编辑器
*/
editor: GlobalActions & {
/**
* 编辑器
*/
editor2: GlobalActions & {
/**
* 编辑器
*/
editor3: GlobalActions
}
}
}
}

/**
Expand Down Expand Up @@ -126,3 +129,20 @@ declare namespace Doc {
}

export = Doc

/**
* vuex 创建 工具函数
* * typescript namespace
*/
export namespace CreateVuex {
import { ActionTree, Store, MutationTree } from 'vuex'
type SniffMutationPayload<T> = T extends (state: any, payload: infer P) => any ? P : T
type SniffMutationPayloadTree<S, M extends MutationTree<S>> = { [K in keyof M]: SniffMutationPayload<M[K]> }
type SniffActionPayload<T> = T extends (state: any, payload: infer P) => infer V
? { payload: P; value: V }
: { payload: unknown; value: unknown }
type SniffActionPayloadTree<S, M extends ActionTree<S, Tstore.state>> = { [K in keyof M]: SniffActionPayload<M[K]> }
type SniffActionPayloadPathTree<S, M extends ActionTree<S, Tstore.state>> = {
[K in keyof M]: SniffMutationPayload<M[K]>
}
}
20 changes: 19 additions & 1 deletion doc/src/store/actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { globalHelper } from 'src/store/helpers'
import { Tstore } from '@types'

export const actions = globalHelper.makeActions({
GET_SERVER_DATA(ctx, { id }: { id: number }) {
Expand All @@ -15,11 +16,28 @@ export const actions = globalHelper.makeActions({

export default actions

export const dispatch = globalHelper.createDispatch<typeof actions>()
export type TActions = typeof actions

export const dispatch = globalHelper.createDispatch<Tstore.Actions>()

// const store = this.store

// dispatch(store, 'GET_SERVER_DATA', { id: 1 }).then(({ id }) => {
// id = 'st'
// id = 1
// })

// dispatch(store, 'editor', 'GET_SERVER_DATA', { id: 1 }).then(({ id }) => {
// id = 'st'
// id = 1
// })

// dispatch(store, 'editor', 'editor2', 'GET_SERVER_DATA', { id: 1 }).then(({ id }) => {
// id = 'st'
// id = 1
// })

// dispatch(store, 'editor', 'editor2', 'editor3', 'GET_SERVER_DATA', { id: 1 }).then(({ id }) => {
// id = 'st'
// id = 1
// })
4 changes: 2 additions & 2 deletions doc/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Tstore } from '@types'

import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import actions, { dispatch } from './actions'
import mutations, { commit, getState } from './mutations'
import getters from './getters'
import state from './state'
Expand All @@ -19,4 +19,4 @@ export function createStore() {
})
}

export { commit, getState }
export { commit, getState, dispatch }
71 changes: 39 additions & 32 deletions doc/src/store/utils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
import { Tstore } from '@types'
import { Tstore, CreateVuex } from '@types'
import { ActionTree, Store, MutationTree } from 'vuex'

export type SniffMutationPayload<T> = T extends (state: any, payload: infer P) => any ? P: T
export type SniffMutationPayloadTree<S, M extends MutationTree<S>> = {
[K in keyof M]: SniffMutationPayload<M[K]>
}

export type SniffActionPayload<T> = T extends (state: any, payload: infer P) => infer V ? { payload: P, value: V }: { payload: unknown, value: unknown }
export type SniffActionPayloadTree<S, M extends ActionTree<S, Tstore.state>> = {
[K in keyof M]: SniffActionPayload<M[K]>
}

export function makeWrapper<T>(namespace: keyof Tstore.state = ('' as any)) {

function createGetState() {
function getState<K extends keyof T>(
context: Store<any>,
Expand All @@ -37,8 +26,7 @@ export function makeWrapper<T>(namespace: keyof Tstore.state = ('' as any)) {
state3Key: K3,
): T[K][K1][K2][K3]
function getState(context: Store<any>, ...args: string[]) {
if (!checkStore(context)) return
checkNamespace(namespace, args)
checkStore(context, { namespace, args })
let result
for (let index = 0; index < args.length; index++) {
const key = args[index];
Expand All @@ -56,7 +44,7 @@ export function makeWrapper<T>(namespace: keyof Tstore.state = ('' as any)) {
}

function createCommit<Mutation extends MutationTree<T>>() {
type MutationPayloadTree = SniffMutationPayloadTree<T, Mutation>
type MutationPayloadTree = CreateVuex.SniffMutationPayloadTree<T, Mutation>
function commit<M extends keyof MutationPayloadTree>(
context: Store<any>,
mutation: M,
Expand All @@ -66,30 +54,29 @@ export function makeWrapper<T>(namespace: keyof Tstore.state = ('' as any)) {
context: Store<any>,
path: P,
mutation: M,
payload: SniffMutationPayloadTree<T, MutationPayloadTree[P]>[M],
payload: CreateVuex.SniffMutationPayloadTree<T, MutationPayloadTree[P]>[M],
): void
function commit<P extends keyof MutationPayloadTree, P1 extends keyof MutationPayloadTree[P], M extends keyof MutationPayloadTree[P][P1]>(
context: Store<any>,
path: P,
path1: P1,
mutation: M,
payload: SniffMutationPayloadTree<T, MutationPayloadTree[P][P1]>[M],
payload: CreateVuex.SniffMutationPayloadTree<T, MutationPayloadTree[P][P1]>[M],
): void
function commit<P extends keyof MutationPayloadTree, P1 extends keyof MutationPayloadTree[P], P2 extends keyof MutationPayloadTree[P][P1], M extends keyof MutationPayloadTree[P][P1][P2]>(
context: Store<any>,
path: P,
path1: P1,
path2: P2,
mutation: M,
payload: SniffMutationPayloadTree<T, MutationPayloadTree[P][P1][P2]>[M],
payload: CreateVuex.SniffMutationPayloadTree<T, MutationPayloadTree[P][P1][P2]>[M],
): void
function commit(context: Store<any>, ...args: any[]) {
if (!checkStore(context)) return
checkStore(context, { namespace, args })
if (args.length < 2) {
console.error('commit args.length must > 2')
return
}
checkNamespace(namespace, args)
const payload = args.pop()
const paths = args.join('/')
return context.commit(paths, payload)
Expand All @@ -104,20 +91,41 @@ export function makeWrapper<T>(namespace: keyof Tstore.state = ('' as any)) {
return actionTree
}

function createDispatch<M extends TActionTree>() {
type actionPayloadTree = SniffActionPayloadTree<T, M>
function dispatch<M extends keyof actionPayloadTree>(
function createDispatch<AT extends TActionTree>() {
type ActionPayloadPathTree = CreateVuex.SniffActionPayloadPathTree<T, AT>
type ActionPayloadTree = CreateVuex.SniffActionPayloadTree<T, AT>
function dispatch<M extends keyof ActionPayloadTree>(
context: Store<any>,
type: M,
payload: actionPayloadTree[M]['payload'],
): actionPayloadTree[M]['value']
payload: ActionPayloadTree[M]['payload'],
): ActionPayloadTree[M]['value']
function dispatch<P extends keyof ActionPayloadPathTree, M extends keyof ActionPayloadPathTree[P]>(
context: Store<any>,
path: P,
type: M,
payload: CreateVuex.SniffActionPayloadTree<ActionPayloadPathTree[P], AT>[M]['payload'],
): CreateVuex.SniffActionPayloadTree<ActionPayloadPathTree[P], AT>[M]['value']
function dispatch<P extends keyof ActionPayloadPathTree, P1 extends keyof ActionPayloadPathTree[P], M extends keyof ActionPayloadPathTree[P][P1]>(
context: Store<any>,
path: P,
path1: P1,
type: M,
payload: CreateVuex.SniffActionPayloadTree<ActionPayloadPathTree[P], AT>[M]['payload'],
): CreateVuex.SniffActionPayloadTree<ActionPayloadPathTree[P], AT>[M]['value']
function dispatch<P extends keyof ActionPayloadPathTree, P1 extends keyof ActionPayloadPathTree[P], P2 extends keyof ActionPayloadPathTree[P][P1], M extends keyof ActionPayloadPathTree[P][P1][P2]>(
context: Store<any>,
path: P,
path1: P1,
path2: P2,
type: M,
payload: CreateVuex.SniffActionPayloadTree<ActionPayloadPathTree[P], AT>[M]['payload'],
): CreateVuex.SniffActionPayloadTree<ActionPayloadPathTree[P], AT>[M]['value']
function dispatch(context: Store<any>, ...args: any[]): any {
if (!checkStore(context)) return
checkStore(context, { namespace, args })
if (args.length < 2) {
console.error('commit args.length must > 2')
return
}
checkNamespace(namespace, args)
const payload = args.pop()
const paths = args.join('/')
return context.dispatch(paths, payload)
Expand All @@ -139,15 +147,14 @@ function isStore(context: Store<any>) {
return 'strict' in context
}

function checkStore(context: Store<any>) {
if (!isStore(context)) {
console.error('checkStore context is not a vuex store!', context)
return false
function checkStore(context: Store<any>, { namespace, args }) {
if (isStore(context)) {
checkNamespace(namespace, args)
}
return true
}

function checkNamespace(namespace: keyof Tstore.state, args: any[]) {
// TODO: 完善深层namespace解析
if (namespace) {
args.unshift(namespace)
}
Expand Down
2 changes: 1 addition & 1 deletion doc/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@
"keyofStringsOnly": true,
"lib": ["dom", "es5", "es6", "scripthost", "es2018.promise", "webworker"]
},
"include": ["tests", "src", "server", "src/**/*.vue", "@types/*"],
"include": ["tests", "src", "server", "src/**/*.vue", "@types"],
"exclude": ["node_modules", "*node_modules*", "dist", "docs", ".tmp", "build"]
}

0 comments on commit 7365ccf

Please sign in to comment.