From c812dd5a9187ac6d5e5fc6db0d1732bbf4786727 Mon Sep 17 00:00:00 2001 From: Mikita Kamkou Date: Sat, 9 Mar 2024 13:18:57 +0100 Subject: [PATCH 1/5] fix(types): Added new mapped type to keep original ref type in the storeToRefs return type (close #2574) --- packages/pinia/src/storeToRefs.ts | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/pinia/src/storeToRefs.ts b/packages/pinia/src/storeToRefs.ts index 76e91c333b..13b5e78161 100644 --- a/packages/pinia/src/storeToRefs.ts +++ b/packages/pinia/src/storeToRefs.ts @@ -11,7 +11,12 @@ import { toRefs, } from 'vue-demi' import { StoreGetters, StoreState } from './store' -import type { PiniaCustomStateProperties, StoreGeneric } from './types' +import type { + _UnwrapAll, + PiniaCustomStateProperties, + Store, + StoreGeneric, +} from './types' type ToComputedRefs = { [K in keyof T]: ToRef extends Ref @@ -19,13 +24,25 @@ type ToComputedRefs = { : ToRef } +/** + * Extracts the refs of a state object from a store. If the state value is a Ref or type that extends ref, it will be kept as is. + * Otherwise, it will be converted into a Ref. + */ +type ToStateRefs = + SS extends Store + ? UnwrappedState extends _UnwrapAll> + ? { + [K in Key]: State[K] extends Ref ? State[K] : Ref + } + : ToRefs + : ToRefs + /** * Extracts the return type for `storeToRefs`. * Will convert any `getters` into `ComputedRef`. */ -export type StoreToRefs = ToRefs< - StoreState & PiniaCustomStateProperties> -> & +export type StoreToRefs = ToStateRefs & + ToRefs>> & ToComputedRefs> /** From 6c97a57716306f2ea2ea631284027ba133f98a78 Mon Sep 17 00:00:00 2001 From: Mikita Kamkou Date: Fri, 15 Mar 2024 19:17:14 +0100 Subject: [PATCH 2/5] test: add types test with custom ref type --- .../pinia/test-dts/customizations.test-d.ts | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/pinia/test-dts/customizations.test-d.ts b/packages/pinia/test-dts/customizations.test-d.ts index ebf3b6435e..7482617134 100644 --- a/packages/pinia/test-dts/customizations.test-d.ts +++ b/packages/pinia/test-dts/customizations.test-d.ts @@ -121,13 +121,16 @@ expectType<{ pinia.use(({ options, store }) => { const { debounce: debounceOptions } = options if (debounceOptions) { - return Object.keys(debounceOptions).reduce((debouncedActions, action) => { - debouncedActions[action] = debounce( - store[action], - debounceOptions[action] - ) - return debouncedActions - }, {} as Record any>) + return Object.keys(debounceOptions).reduce( + (debouncedActions, action) => { + debouncedActions[action] = debounce( + store[action], + debounceOptions[action] + ) + return debouncedActions + }, + {} as Record any> + ) } }) @@ -185,7 +188,28 @@ expectType<{ const double = computed(() => n.value * 2) return { n, - double + double, + } + })() + ) +) + +expectType<{ + n: Ref + customN: Ref & { plusOne: () => void } + double: ComputedRef + myState: Ref + stateOnly: Ref +}>( + storeToRefs( + defineStore('a', () => { + const n = ref(1) + const customN = ref(1) as Ref & { plusOne: () => void } + const double = computed(() => n.value * 2) + return { + n, + customN, + double, } })() ) From a3e96bc0dc32be67137989e900e1389a7ae0207b Mon Sep 17 00:00:00 2001 From: Mikita Kamkou Date: Fri, 29 Mar 2024 12:30:38 +0100 Subject: [PATCH 3/5] test: add type test for an options store that returns custom ref within the state function --- .../pinia/test-dts/customizations.test-d.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/pinia/test-dts/customizations.test-d.ts b/packages/pinia/test-dts/customizations.test-d.ts index 7482617134..34815e09e9 100644 --- a/packages/pinia/test-dts/customizations.test-d.ts +++ b/packages/pinia/test-dts/customizations.test-d.ts @@ -214,3 +214,23 @@ expectType<{ })() ) ) + +expectType<{ + n: Ref + customN: Ref & { plusOne: () => void } + double: ComputedRef + myState: Ref + stateOnly: Ref +}>( + storeToRefs( + defineStore('a', { + state: () => ({ + n: 1, + customN: ref(1) as Ref & { plusOne: () => void }, + }), + getters: { + double: (state) => state.n * 2, + }, + })() + ) +) From 1d545894000d9adc2545d88d1c105aec386c69b4 Mon Sep 17 00:00:00 2001 From: Mikita Kamkou Date: Mon, 1 Apr 2024 13:23:10 +0200 Subject: [PATCH 4/5] fix: Fix case when store has actions --- packages/pinia/src/storeToRefs.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/pinia/src/storeToRefs.ts b/packages/pinia/src/storeToRefs.ts index 13b5e78161..e00ccc15c7 100644 --- a/packages/pinia/src/storeToRefs.ts +++ b/packages/pinia/src/storeToRefs.ts @@ -12,8 +12,11 @@ import { } from 'vue-demi' import { StoreGetters, StoreState } from './store' import type { + _ActionsTree, + _GettersTree, _UnwrapAll, PiniaCustomStateProperties, + StateTree, Store, StoreGeneric, } from './types' @@ -28,14 +31,19 @@ type ToComputedRefs = { * Extracts the refs of a state object from a store. If the state value is a Ref or type that extends ref, it will be kept as is. * Otherwise, it will be converted into a Ref. */ -type ToStateRefs = - SS extends Store +declare type ToStateRefs = + SS extends Store< + string, + infer UnwrappedState, + _GettersTree, + _ActionsTree + > ? UnwrappedState extends _UnwrapAll> ? { - [K in Key]: State[K] extends Ref ? State[K] : Ref + [K in Key]: ToRef } : ToRefs - : ToRefs + : ToRefs> /** * Extracts the return type for `storeToRefs`. From 50aa53b524041cc9dac3ece06c228e3f78a6bd22 Mon Sep 17 00:00:00 2001 From: Mikita Kamkou Date: Mon, 1 Apr 2024 13:23:57 +0200 Subject: [PATCH 5/5] test: add type tests for stores with actions --- .../pinia/test-dts/customizations.test-d.ts | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/packages/pinia/test-dts/customizations.test-d.ts b/packages/pinia/test-dts/customizations.test-d.ts index 34815e09e9..640ae466ad 100644 --- a/packages/pinia/test-dts/customizations.test-d.ts +++ b/packages/pinia/test-dts/customizations.test-d.ts @@ -215,6 +215,33 @@ expectType<{ ) ) +expectType<{ + n: Ref + customN: Ref & { plusOne: () => void } + double: ComputedRef + myState: Ref + stateOnly: Ref +}>( + storeToRefs( + defineStore('a', () => { + const n = ref(1) + const customN = ref(1) as Ref & { plusOne: () => void } + const double = computed(() => n.value * 2) + + function plusOne() { + customN.value++ + } + + return { + n, + customN, + double, + plusOne, + } + })() + ) +) + expectType<{ n: Ref customN: Ref & { plusOne: () => void } @@ -231,6 +258,36 @@ expectType<{ getters: { double: (state) => state.n * 2, }, + actions: { + plusOne() { + this.n++ + }, + }, + })() + ) +) + +expectType<{ + n: Ref + customN: Ref & { plusOne: () => void } + double: ComputedRef + myState: Ref + stateOnly: Ref +}>( + storeToRefs( + defineStore('a', { + state: () => ({ + n: 1, + customN: ref(1) as Ref & { plusOne: () => void }, + }), + getters: { + double: (state) => state.n * 2, + }, + actions: { + plusOne() { + this.n++ + }, + }, })() ) )