+import type Vue from 'vue'
import {
+ GenericStore,
GenericStoreDefinition,
Method,
StateTree,
? StoreObject<L> & Spread<R>
: unknown
+function getCachedStore<
+ Id extends string = string,
+ S extends StateTree = StateTree,
+ G = Record<string, Method>,
+ A = Record<string, Method>
+>(vm: Vue, useStore: StoreDefinition<Id, S, G, A>): Store<Id, S, G, A> {
+ const cache = vm._pStores || (vm._pStores = {})
+ const id = useStore.$id
+ return (cache[id] || (cache[id] = useStore(vm.$pinia))) as Store<Id, S, G, A>
+}
+
/**
- * Allows using stores without the composition API (`setup()`) by generating an object to be spread in the `computed` field of a component.
+ * Allows using stores without the composition API (`setup()`) by generating an
+ * object to be spread in the `computed` field of a component. it accepts a list
+ * of store definitions.
*
* @example
* ```js
* // other computed properties
* ...mapStores(useUserStore, useCartStore)
* },
-
+ *
* created() {
* this.userStore // store with id "user"
* this.cartStore // store with id "cart"
*
* @param stores - list of stores to map to an object
*/
-export function mapStores<Stores extends unknown[]>(
+export function mapStores<Stores extends GenericStoreDefinition[]>(
...stores: [...Stores]
): Spread<Stores> {
return stores.reduce((reduced, useStore) => {
// @ts-ignore: $id is added by defineStore
- reduced[useStore.$id + 'Store'] = function () {
- return (useStore as GenericStoreDefinition)((this as any).$pinia)
+ reduced[useStore.$id + 'Store'] = function (this: Vue) {
+ return getCachedStore(this, useStore)
}
return reduced
}, {} as Spread<Stores>)
): MapStateReturn<S, G> | MapStateObjectReturn<S, G, KeyMapper> {
return Array.isArray(keysOrMapper)
? keysOrMapper.reduce((reduced, key) => {
- // @ts-ignore: too complicated for TS
- reduced[key] = function () {
- return useStore((this as any).$pinia)[key]
+ // @ts-ignore: sorry TS
+ reduced[key] = function (this: Vue) {
+ return getCachedStore(this, useStore)[key]
}
return reduced
}, {} as MapStateReturn<S, G>)
: Object.keys(keysOrMapper).reduce((reduced, key: keyof KeyMapper) => {
- reduced[key] = function () {
- return useStore((this as any).$pinia)[keysOrMapper[key]]
+ reduced[key] = function (this: Vue) {
+ return getCachedStore(this, useStore)[keysOrMapper[key]]
}
return reduced
}, {} as MapStateObjectReturn<S, G, KeyMapper>)
StoreWithState,
StateDescriptor,
PiniaCustomProperties,
+ GenericStore,
} from './types'
import { VueConstructor } from 'vue'
import type Vue from 'vue'
declare module 'vue/types/vue' {
interface Vue {
+ /**
+ * Currently installed pinia instance.
+ */
$pinia: Pinia
+
+ /**
+ * Cache of stores instantiated by the current instance. Used by map
+ * helpers.
+ */
+ _pStores?: Record<string, GenericStore>
}
}
declare module 'vue/types/options' {
interface ComponentOptions<V extends Vue> {
+ /**
+ * Pinia instance to install in your application. Should be passed to the
+ * root Vue.
+ */
pinia?: Pinia
}
}
use(plugin) {
/* istanbul ignore next */
- if (__DEV__) {
+ if (__DEV__ && !__TEST__) {
console.warn(
`[🍍]: The plugin API has plans to change to bring better extensibility. "pinia.use()" signature will change in the next release. It is recommended to avoid using this API.`
)
// : never
// }
-// has the actions without the context (this) for typings
export type Store<
Id extends string,
S extends StateTree,
G,
+ // has the actions without the context (this) for typings
A
> = StoreWithState<Id, S> &
S &
}
/**
- * Generic version of Store
+ * Generic version of Store.
*/
export type GenericStore = Store<
string,
>
/**
- * Generic version of `StoreDefinition`
+ * Generic version of `StoreDefinition`.
*/
-export interface GenericStoreDefinition {
- (pinia?: Pinia | null | undefined): Store<
- string,
- StateTree,
- Record<string, Method>,
- Record<string, Method>
- >
- $id: string
-}
+export type GenericStoreDefinition = StoreDefinition<
+ string,
+ StateTree,
+ Record<string, Method>,
+ Record<string, Method>
+>
export interface DevtoolHook {
on(