* Argument of `store.$onAction()`
*/
export type StoreOnActionListener<
- Id extends string,
- S extends StateTree,
- G extends GettersTree<S>,
- A /* extends ActionsTree */
+ Id extends string = string,
+ S extends StateTree = StateTree,
+ G extends GettersTree<S> = GettersTree<S>,
+ A /* extends ActionsTree */ = ActionsTree
> = (context: StoreOnActionListenerContext<Id, S, G, A>) => void
/**
export interface StoreWithState<
Id extends string,
S extends StateTree,
- G extends GettersTree<S> = GettersTree<S>,
+ G extends GettersTree<StateTree> = GettersTree<S>,
A /* extends ActionsTree */ = ActionsTree
> {
/**
/**
* State of the Store. Setting it will replace the whole state.
*/
- $state: (StateTree extends S ? {} : UnwrapRef<S>) &
- PiniaCustomStateProperties<S>
+ $state: UnwrapRef<S> & PiniaCustomStateProperties<S>
/**
* Private property defining the pinia the store is attached to.
$subscribe(callback: SubscriptionCallback<S>): () => void
/**
- * Array of registered action subscriptions.
+ * Array of registered action subscriptions.Set without the generics to avoid
+ * errors between the generic version of Store and specific stores.
*
* @internal
*/
- _as: StoreOnActionListener<Id, S, G, A>[]
+ _as: StoreOnActionListener[]
/**
* @alpha Please send feedback at https://github.com/posva/pinia/issues/240
G extends GettersTree<S> = GettersTree<S>,
// has the actions without the context (this) for typings
A /* extends ActionsTree */ = ActionsTree
-> = StoreWithState<Id, S, G, A> &
+> = StoreWithState<Id, StateTree extends S ? {} : S, G, A> &
(StateTree extends S ? {} : UnwrapRef<S>) &
(GettersTree<S> extends G ? {} : StoreWithGetters<G>) &
(ActionsTree extends A ? {} : StoreWithActions<A>) &
PiniaCustomStateProperties<S>
/**
- * Generic version of Store. Doesn't fail on access with strings
+ * Generic and type-unsafe version of Store. Doesn't fail on access with
+ * strings, making it much easier to write generic functions that do not care
+ * about the kind of store that is passed.
*/
-export type GenericStore = StoreWithState<
- string,
- StateTree,
- GettersTree<StateTree>,
- ActionsTree
-> &
- PiniaCustomProperties<
- string,
- StateTree,
- GettersTree<StateTree>,
- ActionsTree
- > &
- PiniaCustomStateProperties<StateTree>
+export type GenericStore<
+ Id extends string = string,
+ S extends StateTree = StateTree,
+ G extends GettersTree<S> = GettersTree<S>,
+ // has the actions without the context (this) for typings
+ A /* extends ActionsTree */ = ActionsTree
+> = StoreWithState<Id, S, G, A> &
+ UnwrapRef<S> &
+ StoreWithGetters<G> &
+ StoreWithActions<A> &
+ PiniaCustomProperties<Id, S, G, A> &
+ PiniaCustomStateProperties<S>
/**
* Return type of `defineStore()`. Function that allows instantiating a store.
-import { defineStore, expectType } from './'
+import { watch } from '@vue/runtime-core'
+import { defineStore, expectType, Store, GenericStore } from './'
const useStore = defineStore({
id: 'name',
noA.notExisting
// @ts-expect-error
noG.notExisting
+
+function takeStore<TStore extends Store>(store: TStore): TStore['$id'] {
+ return store.$id
+}
+
+export const useSyncValueToStore = <
+ TStore extends Store,
+ TKey extends keyof TStore['$state']
+>(
+ propGetter: () => TStore[TKey],
+ store: TStore,
+ key: TKey
+): void => {
+ watch(
+ propGetter,
+ (propValue) => {
+ store[key] = propValue
+ },
+ {
+ immediate: true,
+ }
+ )
+}
+
+useSyncValueToStore(() => 'on' as const, store, 'a')
+// @ts-expect-error
+useSyncValueToStore(() => true, store, 'a')
+takeStore(store)
+takeStore(noSAG)
+// @ts-expect-error
+useSyncValueToStore(() => 2, noSAG, 'nope')
+// @ts-expect-error
+useSyncValueToStore(() => null, noSAG, 'myState')
+takeStore(noSA)
+takeStore(noAG)
+useSyncValueToStore(() => 2, noAG, 'myState')
+takeStore(noSG)
+takeStore(noS)
+takeStore(noA)
+useSyncValueToStore(() => 2, noA, 'myState')
+takeStore(noG)
+useSyncValueToStore(() => 2, noG, 'myState')
+
+declare var genericStore: GenericStore
+
+// should not fail like it does with Store
+expectType<any>(genericStore.thing)
+expectType<any>(genericStore.$state.thing)
+takeStore(genericStore)
+useSyncValueToStore(() => 2, genericStore, 'myState')
+useSyncValueToStore(() => 2, genericStore, 'random')
+// @ts-expect-error
+useSyncValueToStore(() => false, genericStore, 'myState')