Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core/types): add chaining derivation support to mapState & mapGetters #674

Merged
merged 11 commits into from
Jan 13, 2021
2 changes: 1 addition & 1 deletion packages/core/@types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export interface MpxComponentIns {

$watch (expr: string | (() => any), handler: WatchHandler | WatchOptWithHandler, options?: WatchOpt): () => void

$forceUpdate (params: object, callback: () => void): void
$forceUpdate (params?: object, callback?: () => void): void

$nextTick (fn: () => void): void

Expand Down
135 changes: 77 additions & 58 deletions packages/core/@types/mpx-store.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
declare namespace MpxStore {
type UnboxDepField<D, F> = F extends keyof D ? D[F] : {}

interface Deps {
[key: string]: Store | StoreWithThis
}

type UnboxDepsField<D extends Deps, F> = string extends keyof D ? {} : {
[K in keyof D]: UnboxDepField<D[K], F>
}
Expand All @@ -13,7 +17,7 @@ declare namespace MpxStore {
[key: string]: (this: void, state: S, ...payload: any[]) => any
}

type Getters<S> = {
interface Getters<S> {
[key: string]: (this: void, state: S, getters: any, globalState: any) => any
}

Expand Down Expand Up @@ -43,11 +47,40 @@ declare namespace MpxStore {

type GetCommit<M, D> = keyof D extends never ? (<T extends keyof M>(type: T, ...payload: M[T] extends (state: any, ...payload: infer P) => any ? P : never) => M[T] extends (state: any, ...payload: any[]) => infer R ? R : never) : ((type: string, ...payload: any[]) => any)

interface Deps {
[key: string]: Store | StoreWithThis
}
interface Store<S = {}, G = {}, M = {}, A = {}, D extends Deps = {}> {

state: S & UnboxDepsField<D, 'state'>
getters: GetGetters<G> & UnboxDepsField<D, 'getters'>
mutations: GetMutations<M> & UnboxDepsField<D, 'mutations'>
actions: GetActions<A> & UnboxDepsField<D, 'actions'>

dispatch: GetDispatch<A, D>

commit: GetCommit<M, D>

mapState<K extends keyof S>(maps: K[]): {
[I in K]: () => S[I]
}
mapState(depPath: string, maps: string[]): object

mapGetters<K extends keyof G>(maps: K[]): {
[I in K]: () => GetGetters<G>[I]
}
mapGetters(depPath: string, maps: string[]): {
[key: string]: () => any
}

mapMutations<K extends keyof M>(maps: K[]): Pick<GetMutations<M>, K>
mapMutations(depPath: string, maps: string[]): {
[key: string]: (...payloads: any[]) => any
}

mapActions<K extends keyof A>(maps: K[]): Pick<GetActions<A>, K>
mapActions(depPath: string, maps: string[]): {
[key: string]: (...payloads: any[]) => any
}

}
type GetComputedSetKeys<T> = {
[K in keyof T]: T[K] extends {
get(): any,
Expand Down Expand Up @@ -77,11 +110,14 @@ declare namespace MpxStore {
interface mapStateFunctionType<S, G> {
[key: string]: (state: S, getter: G) => any
}

interface DeeperMutationsAndActions {
[key: string]: ((...payload: any[]) => any) | MutationsAndActionsWithThis
}

interface DeeperStateAndGetters {
[key: string]: any | DeeperStateAndGetters
}

// Store Type Bindings
type StringKeyof<T> = Exclude<keyof T, symbol>

Expand All @@ -93,15 +129,39 @@ declare namespace MpxStore {
}[CombineStringKey<P, K>]
}[StringKeyof<A>]> // {actA: () => void, storeB.actB: () => void}

type GetAllActionsKey<A, D extends Deps, AK extends 'actions' | 'mutations'> = {
type GetStateAndGettersKey<S, P extends string | number = ''> = UnionToIntersection<{
[K in StringKeyof<S>]: {
[RK in CombineStringKey<P, K>]: S[K] extends DeeperStateAndGetters ? GetStateAndGettersKey<S[K], RK> : Record<RK, S[K]>
}[CombineStringKey<P, K>]
}[StringKeyof<S>]> // {stateA: any, storeB.stateB: any}

type GetAllDepsType<A, D extends Deps, AK extends 'state' | 'getters' | 'actions' | 'mutations'> = {
[K in StringKeyof<A>]: A[K]
anotherso1a marked this conversation as resolved.
Show resolved Hide resolved
} & UnionToIntersection<{
[K in StringKeyof<D>]: {
[K in StringKeyof<D>]: AK extends 'actions' | 'mutations' ? {
[P in keyof GetActionsKey<D[K][AK], K>]: GetActionsKey<D[K][AK], K>[P]
} : { // state, getters
[P in keyof GetStateAndGettersKey<D[K][AK], K>]: GetStateAndGettersKey<D[K][AK], K>[P]
}
}[StringKeyof<D>]>
type GetDispatchAndCommitWithThis<A, D extends Deps, AK extends 'actions' | 'mutations'> = (<T extends keyof GetAllDepsType<A, D, AK>>(type: T, ...payload: GetAllDepsType<A, D, AK>[T] extends (...payload: infer P) => any ? P : never) => GetAllDepsType<A, D, AK>[T] extends (...payload: any[]) => infer R ? R : never)

type GetDispatchAndCommitWithThis<A, D extends Deps, AK extends 'actions' | 'mutations'> = (<T extends keyof GetAllActionsKey<A, D, AK>>(type: T, ...payload: GetAllActionsKey<A, D, AK>[T] extends (...payload: infer P) => any ? P : never) => GetAllActionsKey<A, D, AK>[T] extends (...payload: any[]) => infer R ? R : never)
type GetAllMapKeys<S, D extends Deps, SK extends 'state' | 'getters'> = GetAllDepsType<S, D, SK>

interface StoreOptWithThis<S, G, M, A, D extends Deps> {
state?: S
getters?: G & ThisType<{ state: S & UnboxDepsField<D, 'state'>, getters: GetComputedType<G> & UnboxDepsField<D, 'getters'>, rootState: any }>
mutations?: M & ThisType<{ state: S & UnboxDepsField<D, 'state'> }>
actions?: A & ThisType<{
rootState: any,
state: S & UnboxDepsField<D, 'state'>,
getters: GetComputedType<G> & UnboxDepsField<D, 'getters'>,
dispatch: GetDispatchAndCommitWithThis<A, D, 'actions'>,
commit: GetDispatchAndCommitWithThis<M, D, 'mutations'>
}>
deps?: D
modules?: Record<string, StoreOptWithThis<{}, {}, {}, {}, {}>>
}

interface StoreWithThis<S = {}, G = {}, M = {}, A = {}, D extends Deps = {}> {

Expand All @@ -123,6 +183,10 @@ declare namespace MpxStore {
mapState<T extends mapStateFunctionType<S & UnboxDepsField<D, 'state'>, GetComputedType<G> & UnboxDepsField<D, 'getters'>>>(obj: ThisType<any> & T): {
[I in keyof T]: ReturnType<T[I]>
}
// Support chain derivation
mapState<T extends { [key: string]: keyof GetAllMapKeys<G, D, 'state'> }>(obj: T): {
anotherso1a marked this conversation as resolved.
Show resolved Hide resolved
[I in keyof T]: GetAllMapKeys<G, D, 'state'>[T[I]]
}
mapState<T extends { [key: string]: keyof S }>(obj: T): {
[I in keyof T]: () => S[T[I]]
}
Expand All @@ -134,9 +198,14 @@ declare namespace MpxStore {
mapGetters(depPath: string, maps: string[]): {
anotherso1a marked this conversation as resolved.
Show resolved Hide resolved
[key: string]: () => any
}
// Support chain derivation
mapGetters<T extends { [key: string]: keyof GetAllMapKeys<G, D, 'getters'> }>(obj: T): {
[I in keyof T]: GetAllMapKeys<G, D, 'getters'>[T[I]]
}
mapGetters<T extends { [key: string]: keyof G }>(obj: T): {
[I in keyof T]: G[T[I]]
}
// When importing js in ts file, use this method to be compatible
mapGetters<T extends { [key: string]: string }>(obj: T): {
[I in keyof T]: (...payloads: any[]) => any
}
Expand Down Expand Up @@ -165,56 +234,6 @@ declare namespace MpxStore {

}

interface StoreOptWithThis<S, G, M, A, D extends Deps> {
state?: S
getters?: G & ThisType<{ state: S & UnboxDepsField<D, 'state'>, getters: GetComputedType<G> & UnboxDepsField<D, 'getters'>, rootState: any }>
mutations?: M & ThisType<{ state: S & UnboxDepsField<D, 'state'> }>
actions?: A & ThisType<{
rootState: any,
state: S & UnboxDepsField<D, 'state'>,
getters: GetComputedType<G> & UnboxDepsField<D, 'getters'>,
dispatch: GetDispatchAndCommitWithThis<A, D, 'actions'>,
commit: GetDispatchAndCommitWithThis<M, D, 'mutations'>
}>
deps?: D
modules?: Record<string, StoreOptWithThis<{}, {}, {}, {}, {}>>
}

interface Store<S = {}, G = {}, M = {}, A = {}, D extends Deps = {}> {

state: S & UnboxDepsField<D, 'state'>
getters: GetGetters<G> & UnboxDepsField<D, 'getters'>
mutations: GetMutations<M> & UnboxDepsField<D, 'mutations'>
actions: GetActions<A> & UnboxDepsField<D, 'actions'>

dispatch: GetDispatch<A, D>

commit: GetCommit<M, D>

mapState<K extends keyof S>(maps: K[]): {
[I in K]: () => S[I]
}
mapState(depPath: string, maps: string[]): object

mapGetters<K extends keyof G>(maps: K[]): {
[I in K]: () => GetGetters<G>[I]
}
mapGetters(depPath: string, maps: string[]): {
[key: string]: () => any
}

mapMutations<K extends keyof M>(maps: K[]): Pick<GetMutations<M>, K>
mapMutations(depPath: string, maps: string[]): {
[key: string]: (...payloads: any[]) => any
}

mapActions<K extends keyof A>(maps: K[]): Pick<GetActions<A>, K>
mapActions(depPath: string, maps: string[]): {
[key: string]: (...payloads: any[]) => any
}

}

interface StoreOpt<S, G, M, A, D extends Deps> {
state?: S,
getters?: G
Expand Down