--- /dev/null
+import { computed, ref, ToRefs } from 'vue'
+import { createPinia, defineStore, setActivePinia, storeToRefs } from '../src'
+
+describe('storeToRefs', () => {
+ beforeEach(() => {
+ setActivePinia(createPinia())
+ })
+
+ function objectOfRefs<O extends Record<any, any>>(o: O): ToRefs<O> {
+ return Object.keys(o).reduce((newO, key) => {
+ // @ts-expect-error: we only need to match
+ newO[key] = expect.objectContaining({ value: o[key] })
+ return newO
+ }, {} as ToRefs<O>)
+ }
+
+ it('empty state', () => {
+ expect(storeToRefs(defineStore('a', {})())).toEqual({})
+ expect(storeToRefs(defineStore('a', () => {})())).toEqual({})
+ expect(storeToRefs(defineStore({ id: 'a' })())).toEqual({})
+ })
+
+ it('empty getters', () => {
+ expect(
+ storeToRefs(
+ defineStore('a', {
+ state: () => ({ n: 0 }),
+ })()
+ )
+ ).toEqual(objectOfRefs({ n: 0 }))
+ expect(
+ storeToRefs(
+ defineStore('a', () => {
+ return { n: ref(0) }
+ })()
+ )
+ ).toEqual(objectOfRefs({ n: 0 }))
+ })
+
+ it('contains getters', () => {
+ expect(
+ storeToRefs(
+ defineStore('a', {
+ state: () => ({ n: 1 }),
+ getters: {
+ double: (state) => state.n * 2,
+ },
+ })()
+ )
+ ).toEqual(objectOfRefs({ n: 1, double: 2 }))
+ expect(
+ storeToRefs(
+ defineStore('a', () => {
+ const n = ref(0)
+ const double = computed(() => n.value * 2)
+ return { n, double }
+ })()
+ )
+ ).toEqual(objectOfRefs({ n: 1, double: 2 }))
+ })
+
+ it('contain plugin states', () => {
+ const pinia = createPinia()
+ // directly push because no app
+ pinia._p.push(() => ({
+ // @ts-expect-error: cannot set a ref yet
+ pluginN: ref(20),
+ // should not appear in refs
+ shared: 10,
+ }))
+ setActivePinia(pinia)
+
+ expect(
+ storeToRefs(
+ defineStore('a', {
+ state: () => ({ n: 0 }),
+ })()
+ )
+ ).toEqual(objectOfRefs({ n: 0, pluginN: 20 }))
+ expect(
+ storeToRefs(
+ defineStore('a', () => {
+ return { n: ref(0) }
+ })()
+ )
+ ).toEqual(objectOfRefs({ n: 0, pluginN: 20 }))
+ })
+
+ tds(() => {
+ const store1 = defineStore('a', () => {
+ const n = ref(0)
+ const double = computed(() => n.value * 2)
+ return { n, double }
+ })()
+
+ storeToRefs(store1).double
+ })
+
+ function tds(_fn: Function) {}
+})
--- /dev/null
+import { isReactive, isRef, toRaw, toRef, ToRefs } from 'vue-demi'
+import { StoreGetters, StoreState } from './store'
+import type { PiniaCustomStateProperties, StoreGeneric } from './types'
+
+/**
+ * Creates an object of references with all the state, getters, and plugin-added
+ * state properties of the store. Similar to `toRefs()` but specifically
+ * designed for Pinia stores so methods and non reactive properties are
+ * completely ignored.
+ *
+ * @param store - store to extract the refs from
+ */
+export function storeToRefs<SS extends StoreGeneric>(
+ store: SS
+): ToRefs<
+ StoreState<SS> & StoreGetters<SS> & PiniaCustomStateProperties<StoreState<SS>>
+> {
+ store = toRaw(store)
+
+ const refs = {} as ToRefs<
+ StoreState<SS> &
+ StoreGetters<SS> &
+ PiniaCustomStateProperties<StoreState<SS>>
+ >
+ for (const key in store) {
+ const value = store[key]
+ if (isRef(value) || isReactive(value)) {
+ // @ts-expect-error: the key is state or getter
+ refs[key] =
+ // ---
+ toRef(store, key)
+ }
+ }
+
+ return refs
+}
defineStore,
mapStores,
ActionsTree,
+ storeToRefs,
} from './'
import { App, ref, Ref } from 'vue'
}, {} as Record<string, (...args: any[]) => any>)
}
})
+
+expectType<{ myState: Ref<number>; stateOnly: Ref<number> }>(
+ storeToRefs(defineStore('a', {})())
+)
+
+expectType<{
+ a: Ref<boolean>
+ myState: Ref<number>
+ stateOnly: Ref<number>
+}>(
+ // @ts-expect-error: no a
+ storeToRefs(defineStore('a', {})())
+)
+
+expectType<{
+ $onAction: Ref<unknown>
+ myState: Ref<number>
+ stateOnly: Ref<number>
+}>(
+ // @ts-expect-error: doesn't add store methods
+ storeToRefs(defineStore('a', {})())
+)
+
+expectType<{ a: Ref<boolean>; myState: Ref<number>; stateOnly: Ref<number> }>(
+ storeToRefs(defineStore('a', { state: () => ({ a: true }) })())
+)
+
+expectType<{
+ n: Ref<number>
+ double: Ref<number>
+ myState: Ref<number>
+ stateOnly: Ref<number>
+}>(
+ storeToRefs(
+ defineStore('a', {
+ state: () => ({ n: 1 }),
+ getters: {
+ double: (state) => state.n * 2,
+ },
+ })()
+ )
+)