]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
fix(types): unwrap refs passed to state
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 12 May 2021 07:52:22 +0000 (09:52 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 12 May 2021 07:52:22 +0000 (09:52 +0200)
Fix #491

__tests__/state.spec.ts
src/store.ts
src/types.ts
test-dts/state.test-d.ts [new file with mode: 0644]

index 5734913404b7c21670bfc7b9dc701b3c2b34828f..1fb8f0fdd5300d6dbc4d219310e3c47c65695524 100644 (file)
@@ -1,5 +1,5 @@
 import { createPinia, defineStore, setActivePinia } from '../src'
-import { computed, nextTick, watch } from 'vue'
+import { computed, nextTick, ref, watch } from 'vue'
 
 describe('State', () => {
   const useStore = () => {
@@ -49,4 +49,33 @@ describe('State', () => {
     await nextTick()
     expect(spy).toHaveBeenCalledTimes(1)
   })
+
+  it('unwraps refs', () => {
+    const name = ref('Eduardo')
+    const counter = ref(0)
+    const double = computed({
+      get: () => counter.value * 2,
+      set(val) {
+        counter.value = val / 2
+      },
+    })
+
+    setActivePinia(createPinia())
+    const useStore = defineStore({
+      id: 'main',
+      state: () => ({
+        name,
+        counter,
+        double,
+      }),
+    })
+
+    const store = useStore()
+
+    expect(store.name).toBe('Eduardo')
+    name.value = 'Ed'
+    expect(store.name).toBe('Ed')
+    store.name = 'Edu'
+    expect(store.name).toBe('Edu')
+  })
 })
index 41e5f9cbda4c195d8f7c35c1f153978cfd89bed1..e8b7e891ecac41dce8396f16830b0f4e516fafc0 100644 (file)
@@ -10,6 +10,7 @@ import {
   provide,
   DebuggerEvent,
   WatchOptions,
+  UnwrapRef,
 } from 'vue'
 import {
   StateTree,
@@ -135,7 +136,7 @@ function initStore<Id extends string, S extends StateTree>(
     subscriptions.forEach((callback) => {
       callback(
         { storeName: $id, type, payload: partialState, events: debuggerEvents },
-        pinia.state.value[$id]
+        pinia.state.value[$id] as UnwrapRef<S>
       )
     })
   }
@@ -163,7 +164,7 @@ function initStore<Id extends string, S extends StateTree>(
       }
     }
     const stopWatcher = watch(
-      () => pinia.state.value[$id],
+      () => pinia.state.value[$id] as UnwrapRef<S>,
       (state, oldState) => {
         if (isListening) {
           // TODO: remove payload
index a1c56e0285edc43882bf754201489c3da5f26419..49165d7b83d3fa5d7d980623a4de0054f974c50c 100644 (file)
@@ -1,4 +1,4 @@
-import { DebuggerEvent } from 'vue'
+import { DebuggerEvent, UnwrapRef } from 'vue'
 import { Pinia } from './rootStore'
 
 /**
@@ -112,9 +112,9 @@ export type SubscriptionCallback<S> = (
      */
     events?: DebuggerEvent[] | DebuggerEvent
 
-    payload: DeepPartial<S>
+    payload: DeepPartial<UnwrapRef<S>>
   },
-  state: S
+  state: UnwrapRef<S>
 ) => void
 
 /**
@@ -130,7 +130,7 @@ export interface StoreWithState<Id extends string, S extends StateTree> {
   /**
    * State of the Store. Setting it will replace the whole state.
    */
-  $state: S
+  $state: UnwrapRef<S>
 
   /**
    * Private property defining the pinia the store is attached to.
@@ -281,7 +281,7 @@ export type Store<
   // has the actions without the context (this) for typings
   A
 > = StoreWithState<Id, S> &
-  S &
+  UnwrapRef<S> &
   StoreWithGetters<G> &
   StoreWithActions<A> &
   PiniaCustomProperties<Id, S, G, A>
@@ -347,7 +347,7 @@ export interface PiniaCustomProperties<
  */
 export type GettersTree<S extends StateTree> = Record<
   string,
-  ((state: S) => any) | (() => any)
+  ((state: UnwrapRef<S>) => any) | (() => any)
 >
 
 /**
@@ -371,14 +371,15 @@ export interface DefineStoreOptions<
   /**
    * Optional object of getters.
    */
-  getters?: G & ThisType<S & StoreWithGetters<G> & PiniaCustomProperties>
+  getters?: G &
+    ThisType<UnwrapRef<S> & StoreWithGetters<G> & PiniaCustomProperties>
   /**
    * Optional object of actions.
    */
   actions?: A &
     ThisType<
       A &
-        S &
+        UnwrapRef<S> &
         StoreWithState<Id, S> &
         StoreWithGetters<G> &
         PiniaCustomProperties
diff --git a/test-dts/state.test-d.ts b/test-dts/state.test-d.ts
new file mode 100644 (file)
index 0000000..671e2bc
--- /dev/null
@@ -0,0 +1,48 @@
+import { computed, ref } from 'vue'
+import { defineStore, expectType } from './'
+
+const name = ref('Eduardo')
+const counter = ref(0)
+const double = computed({
+  get: () => counter.value * 2,
+  set(val) {
+    counter.value = val / 2
+  },
+})
+
+const useStore = defineStore({
+  id: 'name',
+  state: () => ({
+    n: 0,
+    name,
+    double,
+    counter,
+  }),
+
+  getters: {
+    myDouble: (state) => {
+      expectType<number>(state.double)
+      expectType<number>(state.counter)
+      return state.n * 2
+    },
+    other(): undefined {
+      expectType<number>(this.double)
+      expectType<number>(this.counter)
+      return undefined
+    },
+  },
+
+  actions: {
+    some() {
+      expectType<number>(this.$state.double)
+      expectType<number>(this.$state.counter)
+      expectType<number>(this.double)
+      expectType<number>(this.counter)
+    },
+  },
+})
+
+const store = useStore()
+
+expectType<number>(store.$state.counter)
+expectType<number>(store.$state.double)