UNPKG

vuex-tstore

Version:

Provides a low-overhead TypeScript wrapper around Vuex that can trigger compilation errors and IntelliSense tips.

97 lines (88 loc) 3.54 kB
/** * Defines how to manage the mutation proxies. */ import { Store as VuexStore } from "vuex"; import { Payload, PayloadReturn, qualifyKey } from "./util"; /** * Extracts an interface for wrapped mutation accessors. * * This somewhat beastly looking template is used to generate an interface for * a wrapper around a mutation object. That is, given an object where each * property is a function in the form `(store, payload?) => void`, a wrapper * could be made with matching properties where each property is in the form * `(payload?) => void`. In such an object, the `store` argument should be * automatically filled in with the store object being wrapped. * * Given an object of type `TMutations` (below), this type reflects that there * exists an interface of type `TWrappedMutations` (below). * * ```typescript * interface TMutations { * [key: string | number | Symbol]: (context: TContext, payload?: TPayload) => TResult * } * * type TWrappedMutations = { * [key in keyof TMutations]: (payload?: TPayload) => TResult * } * ``` */ export type WrappedMutations<TMutations> = { [Key in keyof TMutations]: WrappedMutationHandler<TMutations[Key]> & { listen(handler: MutationListenerHandler<TMutations[Key]>): () => void; } }; /** * Provides a generic interface for a wrapper around a `TMutation` function. * * This automatically differentiates the mutations that have payloads from the * mutations that do not have payloads. */ type WrappedMutationHandler<TMutation> = TMutation extends (store: any) => void ? () => ReturnType<TMutation> : (payload: Payload<TMutation>) => PayloadReturn<TMutation>; /** * Provides a generic interface for a mutation event-listener function. */ type MutationListenerHandler<TMutation> = TMutation extends (store: any) => void ? () => void : (payload: Payload<TMutation>) => void; /** * Wraps mutation accessors to create a set of mutation proxies. * * Yet another function that bypasses the type system for convenience. This * function does what it claims to do, but has to tell TypeScript to trust that * we know what we are doing. As always, change this function with caution, * because if this function breaks then we lose IntelliSense around mutations. * * @param onMutate The mutation function from the store. * @param accessors The accessor functions. * @param store The store to wrap mutations around. * @param mutations The mutation accessors to wrap. */ export function wrapMutations< TRootState, TMutations extends object, TWrappedMutations = WrappedMutations<TMutations> >( namespace: string, store: VuexStore<TRootState>, mutations: TMutations ): TWrappedMutations { return Object.entries(mutations).reduce((commit, [key, mutation]) => { // Get the key that Vuex knows this mutation by. const mutationKey = qualifyKey(mutation, namespace); // Prepare the function/listeners to give back to the store. type TMutationHandler = WrappedMutationHandler<typeof mutation> & Partial<typeof mutation>; const deferred: TMutationHandler = payload => store.commit(mutationKey, payload, { root: true }); deferred.listen = (handler: MutationListenerHandler<typeof mutation>) => store.subscribe(({ type, payload }) => { if (type === mutationKey) { (handler as any).call(null, payload); } }); // Attach the deferment to the commit function. return Object.defineProperty(commit, key, { value: deferred }); }, {}) as TWrappedMutations; }