From: Eduardo San Martin Morote Date: Wed, 12 May 2021 07:52:22 +0000 (+0200) Subject: fix(types): unwrap refs passed to state X-Git-Tag: v2.0.0-alpha.17~32 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=b2d3ac994f0d1778d82fd0e5b14915fee4c5cb2b;p=thirdparty%2Fvuejs%2Fpinia.git fix(types): unwrap refs passed to state Fix #491 --- diff --git a/__tests__/state.spec.ts b/__tests__/state.spec.ts index 57349134..1fb8f0fd 100644 --- a/__tests__/state.spec.ts +++ b/__tests__/state.spec.ts @@ -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') + }) }) diff --git a/src/store.ts b/src/store.ts index 41e5f9cb..e8b7e891 100644 --- a/src/store.ts +++ b/src/store.ts @@ -10,6 +10,7 @@ import { provide, DebuggerEvent, WatchOptions, + UnwrapRef, } from 'vue' import { StateTree, @@ -135,7 +136,7 @@ function initStore( subscriptions.forEach((callback) => { callback( { storeName: $id, type, payload: partialState, events: debuggerEvents }, - pinia.state.value[$id] + pinia.state.value[$id] as UnwrapRef ) }) } @@ -163,7 +164,7 @@ function initStore( } } const stopWatcher = watch( - () => pinia.state.value[$id], + () => pinia.state.value[$id] as UnwrapRef, (state, oldState) => { if (isListening) { // TODO: remove payload diff --git a/src/types.ts b/src/types.ts index a1c56e02..49165d7b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { DebuggerEvent } from 'vue' +import { DebuggerEvent, UnwrapRef } from 'vue' import { Pinia } from './rootStore' /** @@ -112,9 +112,9 @@ export type SubscriptionCallback = ( */ events?: DebuggerEvent[] | DebuggerEvent - payload: DeepPartial + payload: DeepPartial> }, - state: S + state: UnwrapRef ) => void /** @@ -130,7 +130,7 @@ export interface StoreWithState { /** * State of the Store. Setting it will replace the whole state. */ - $state: S + $state: UnwrapRef /** * 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 & - S & + UnwrapRef & StoreWithGetters & StoreWithActions & PiniaCustomProperties @@ -347,7 +347,7 @@ export interface PiniaCustomProperties< */ export type GettersTree = Record< string, - ((state: S) => any) | (() => any) + ((state: UnwrapRef) => any) | (() => any) > /** @@ -371,14 +371,15 @@ export interface DefineStoreOptions< /** * Optional object of getters. */ - getters?: G & ThisType & PiniaCustomProperties> + getters?: G & + ThisType & StoreWithGetters & PiniaCustomProperties> /** * Optional object of actions. */ actions?: A & ThisType< A & - S & + UnwrapRef & StoreWithState & StoreWithGetters & PiniaCustomProperties diff --git a/test-dts/state.test-d.ts b/test-dts/state.test-d.ts new file mode 100644 index 00000000..671e2bcd --- /dev/null +++ b/test-dts/state.test-d.ts @@ -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(state.double) + expectType(state.counter) + return state.n * 2 + }, + other(): undefined { + expectType(this.double) + expectType(this.counter) + return undefined + }, + }, + + actions: { + some() { + expectType(this.$state.double) + expectType(this.$state.counter) + expectType(this.double) + expectType(this.counter) + }, + }, +}) + +const store = useStore() + +expectType(store.$state.counter) +expectType(store.$state.double)