]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
refactor(types): better getter types
authorEduardo San Martin Morote <posva13@gmail.com>
Thu, 29 Apr 2021 14:21:17 +0000 (16:21 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Thu, 29 Apr 2021 14:21:17 +0000 (16:21 +0200)
13 files changed:
__tests__/getters.spec.ts
__tests__/lifespan.spec.ts
__tests__/mapHelpers.spec.ts
__tests__/pinia/stores/cart.ts
__tests__/pinia/stores/user.ts
__tests__/storePlugins.spec.ts
src/mapHelpers.ts
src/rootStore.ts
src/store.ts
src/types.ts
test-dts/deprecated.test-d.ts
test-dts/mapHelpers.test-d.ts
test-dts/store.test-d.ts

index 26d04f6f3f3c593b19bc0dd80ff820d25686091d..28352989dd5952b3b5548a2c17718599928e7424 100644 (file)
@@ -10,13 +10,13 @@ describe('Getters', () => {
         name: 'Eduardo',
       }),
       getters: {
-        upperCaseName() {
-          return this.name.toUpperCase()
+        upperCaseName(store) {
+          return store.name.toUpperCase()
         },
-        doubleName() {
+        doubleName(): string {
           return this.upperCaseName
         },
-        composed() {
+        composed(): string {
           return this.upperCaseName + ': ok'
         },
       },
@@ -32,7 +32,7 @@ describe('Getters', () => {
     id: 'A',
     state: () => ({ a: 'a' }),
     getters: {
-      fromB() {
+      fromB(): string {
         const bStore = useB()
         return this.a + ' ' + bStore.b
       },
index a299b346c4473e7fb1baa748f7a65983193bdcc6..aef85fb747916f9c48d631abf0b211dfd3c6908d 100644 (file)
@@ -15,11 +15,11 @@ describe('Store Lifespan', () => {
         },
       }),
       getters: {
-        double() {
-          return this.n * 2
+        double(state) {
+          return state.n * 2
         },
-        notA() {
-          return !this.a
+        notA(state) {
+          return !state.a
         },
       },
     })
index cdd1f0742feeda768ecee6fa7b19d620ba5adc81..d917e446be56c1702961f8e8ed5625717635ab5b 100644 (file)
@@ -25,11 +25,11 @@ describe('Map Helpers', () => {
       },
     }),
     getters: {
-      double() {
-        return this.n * 2
+      double(state) {
+        return state.n * 2
       },
-      notA() {
-        return !this.a
+      notA(state) {
+        return !state.a
       },
     },
     actions: {
index 13aadf39d63ae908c4d856ad8db424b4a7b29357..eca0d1f3f01b514eac76f239a678f50f844d1286 100644 (file)
@@ -8,8 +8,8 @@ export const useCartStore = defineStore({
     rawItems: [] as string[],
   }),
   getters: {
-    items() {
-      return this.rawItems.reduce((items, item) => {
+    items: (state) =>
+      state.rawItems.reduce((items, item) => {
         const existingItem = items.find((it) => it.name === item)
 
         if (!existingItem) {
@@ -19,9 +19,9 @@ export const useCartStore = defineStore({
         }
 
         return items
-      }, [] as { name: string; amount: number }[])
-    },
+      }, [] as { name: string; amount: number }[]),
   },
+
   actions: {
     addItem(name: string) {
       this.rawItems.push(name)
index 956fb1d449e3c0d6757e95457f729b6749452720..64fab17e680008200c09d6771ba0ee06118b424d 100644 (file)
@@ -31,8 +31,8 @@ export const useUserStore = defineStore({
     },
   },
   getters: {
-    test() {
-      return this.name.toUpperCase()
+    test(state) {
+      return state.name.toUpperCase()
     },
   },
 })
index fde8ccf3eb853fcfb73895cf3fc9090c30df984b..ef75b81e3534f43ce05ea1682c9b5df52ce54b7a 100644 (file)
@@ -24,9 +24,7 @@ describe('store plugins', () => {
     },
 
     getters: {
-      doubleN() {
-        return this.n * 2
-      },
+      doubleN: (state) => state.n * 2,
     },
   })
 
index eaa4d3c0d6324288974cfe15da0ac08bc630b230..d7a9ac4c4e9b5b7170adacd9f90ff7ed701094ca 100644 (file)
@@ -1,6 +1,7 @@
 import { ComponentInstance } from '@vue/devtools-api'
 import {
   GenericStore,
+  GettersTree,
   Method,
   StateTree,
   Store,
@@ -48,7 +49,7 @@ type Spread<A extends readonly any[]> = A extends [infer L, ...infer R]
 function getCachedStore<
   Id extends string = string,
   S extends StateTree = StateTree,
-  G = Record<string, Method>,
+  G extends GettersTree<S> = GettersTree<S>,
   A = Record<string, Method>
 >(
   vm: ComponentInstance,
@@ -122,14 +123,14 @@ export function mapStores<Stores extends any[]>(
   }, {} as Spread<Stores>)
 }
 
-type MapStateReturn<S extends StateTree, G> = {
+type MapStateReturn<S extends StateTree, G extends GettersTree<S>> = {
   [key in keyof S | keyof G]: () => Store<string, S, G, {}>[key]
 }
 
 type MapStateObjectReturn<
   Id extends string,
   S extends StateTree,
-  G,
+  G extends GettersTree<S>,
   A,
   T extends Record<
     string,
@@ -182,7 +183,7 @@ type MapStateObjectReturn<
 export function mapState<
   Id extends string,
   S extends StateTree,
-  G,
+  G extends GettersTree<S>,
   A,
   KeyMapper extends Record<
     string,
@@ -215,7 +216,12 @@ export function mapState<
  * @param useStore - store to map from
  * @param keys - array of state properties or getters
  */
-export function mapState<Id extends string, S extends StateTree, G, A>(
+export function mapState<
+  Id extends string,
+  S extends StateTree,
+  G extends GettersTree<S>,
+  A
+>(
   useStore: StoreDefinition<Id, S, G, A>,
   keys: Array<keyof S | keyof G>
 ): MapStateReturn<S, G>
@@ -230,7 +236,7 @@ export function mapState<Id extends string, S extends StateTree, G, A>(
 export function mapState<
   Id extends string,
   S extends StateTree,
-  G,
+  G extends GettersTree<S>,
   A,
   KeyMapper extends Record<
     string,
@@ -303,7 +309,7 @@ type MapActionsObjectReturn<A, T extends Record<string, keyof A>> = {
 export function mapActions<
   Id extends string,
   S extends StateTree,
-  G,
+  G extends GettersTree<S>,
   A,
   KeyMapper extends Record<string, keyof A>
 >(
@@ -333,7 +339,12 @@ export function mapActions<
  * @param useStore - store to map from
  * @param keys - array of action names to map
  */
-export function mapActions<Id extends string, S extends StateTree, G, A>(
+export function mapActions<
+  Id extends string,
+  S extends StateTree,
+  G extends GettersTree<S>,
+  A
+>(
   useStore: StoreDefinition<Id, S, G, A>,
   keys: Array<keyof A>
 ): MapActionsReturn<A>
@@ -348,7 +359,7 @@ export function mapActions<Id extends string, S extends StateTree, G, A>(
 export function mapActions<
   Id extends string,
   S extends StateTree,
-  G,
+  G extends GettersTree<S>,
   A,
   KeyMapper extends Record<string, keyof A>
 >(
@@ -398,7 +409,7 @@ type MapWritableStateObjectReturn<
 export function mapWritableState<
   Id extends string,
   S extends StateTree,
-  G,
+  G extends GettersTree<S>,
   A,
   KeyMapper extends Record<string, keyof S>
 >(
@@ -413,7 +424,12 @@ export function mapWritableState<
  * @param useStore - store to map from
  * @param keys - array of state properties
  */
-export function mapWritableState<Id extends string, S extends StateTree, G, A>(
+export function mapWritableState<
+  Id extends string,
+  S extends StateTree,
+  G extends GettersTree<S>,
+  A
+>(
   useStore: StoreDefinition<Id, S, G, A>,
   keys: Array<keyof S>
 ): MapWritableStateReturn<S>
@@ -428,7 +444,7 @@ export function mapWritableState<Id extends string, S extends StateTree, G, A>(
 export function mapWritableState<
   Id extends string,
   S extends StateTree,
-  G,
+  G extends GettersTree<S>,
   A,
   KeyMapper extends Record<string, keyof S>
 >(
index dd4f1c22327c75f9825c6b2565d1502280223313..c3b601f22dd1f3fd5e050d3de48b1c2b616ca43b 100644 (file)
@@ -9,6 +9,7 @@ import {
   Method,
   DefineStoreOptions,
   Store,
+  GettersTree,
 } from './types'
 
 /**
@@ -72,7 +73,7 @@ export const getClientApp = () => clientApp
 export interface PiniaPluginContext<
   Id extends string = string,
   S extends StateTree = StateTree,
-  G = Record<string, Method>,
+  G extends GettersTree<S> = GettersTree<S>,
   A = Record<string, Method>
 > {
   /**
index fe96a9242e23526f0eb6a83b861f2805151f9af5..0258408756416e16efd5e96bbe8b2941bd72ad6f 100644 (file)
@@ -23,6 +23,7 @@ import {
   DefineStoreOptions,
   StoreDefinition,
   GenericStore,
+  GettersTree,
 } from './types'
 import {
   getActivePinia,
@@ -215,7 +216,7 @@ function initStore<Id extends string, S extends StateTree>(
 function buildStoreToUse<
   Id extends string,
   S extends StateTree,
-  G extends Record<string, Method>,
+  G extends GettersTree<S>,
   A extends Record<string, Method>
 >(
   partialStore: StoreWithState<Id, S>,
@@ -233,6 +234,7 @@ function buildStoreToUse<
     computedGetters[getterName] = computed(() => {
       setActivePinia(pinia)
       // eslint-disable-next-line @typescript-eslint/no-use-before-define
+      // @ts-expect-error: the argument count is correct
       return getters[getterName].call(store, store)
     }) as StoreWithGetters<G>[typeof getterName]
   }
@@ -281,7 +283,7 @@ export function defineStore<
   Id extends string,
   S extends StateTree,
   // the omission of the extends is necessary for type inference
-  G /* extends Record<string, Method> */,
+  G extends GettersTree<S>,
   A /* extends Record<string, Method> */
 >(options: DefineStoreOptions<Id, S, G, A>): StoreDefinition<Id, S, G, A> {
   const { id, state, getters, actions } = options
@@ -314,7 +316,7 @@ export function defineStore<
         storeAndDescriptor[0],
         storeAndDescriptor[1],
         id,
-        getters as Record<string, Method> | undefined,
+        getters as GettersTree<S> | undefined,
         actions as Record<string, Method> | undefined,
         // @ts-ignore: because we don't have extend on G and A
         options
@@ -357,7 +359,7 @@ export function defineStore<
         storeAndDescriptor[0],
         storeAndDescriptor[1],
         id,
-        getters as Record<string, Method> | undefined,
+        getters as GettersTree<S> | undefined,
         actions as Record<string, Method> | undefined,
         // @ts-ignore: because we don't have extend on G and A
         options
index bd1ed9adc9de23d7a7045c148c1aff3b28369faa..6163b00eb7f29648d1ac8c87695c450917903694 100644 (file)
@@ -144,7 +144,7 @@ export type StoreWithGetters<G> = {
 export type Store<
   Id extends string,
   S extends StateTree,
-  G,
+  G extends GettersTree<S>,
   // has the actions without the context (this) for typings
   A
 > = StoreWithState<Id, S> &
@@ -153,13 +153,15 @@ export type Store<
   StoreWithActions<A> &
   PiniaCustomProperties<Id, S, G, A>
 
+// TODO: check if it's possible to add = to StoreDefinition and Store and cleanup GenericStore and the other one
+
 /**
  * Return type of `defineStore()`. Function that allows instantiating a store.
  */
 export interface StoreDefinition<
   Id extends string,
   S extends StateTree,
-  G /* extends Record<string, StoreGetterThis> */,
+  G extends GettersTree<S>,
   A /* extends Record<string, StoreAction> */
 > {
   (pinia?: Pinia | null | undefined): Store<Id, S, G, A>
@@ -172,7 +174,7 @@ export interface StoreDefinition<
 export type GenericStore = Store<
   string,
   StateTree,
-  Record<string, Method>,
+  GettersTree<StateTree>,
   Record<string, Method>
 >
 
@@ -182,7 +184,7 @@ export type GenericStore = Store<
 export type GenericStoreDefinition = StoreDefinition<
   string,
   StateTree,
-  Record<string, Method>,
+  GettersTree<StateTree>,
   Record<string, Method>
 >
 
@@ -192,10 +194,15 @@ export type GenericStoreDefinition = StoreDefinition<
 export interface PiniaCustomProperties<
   Id extends string = string,
   S extends StateTree = StateTree,
-  G = Record<string, Method>,
+  G extends GettersTree<S> = GettersTree<S>,
   A = Record<string, Method>
 > {}
 
+export type GettersTree<S extends StateTree> = Record<
+  string,
+  ((state: S) => any) | (() => any)
+>
+
 /**
  * Options parameter of `defineStore()`. Can be extended to augment stores with
  * the plugin API.
@@ -203,7 +210,7 @@ export interface PiniaCustomProperties<
 export interface DefineStoreOptions<
   Id extends string,
   S extends StateTree,
-  G /* extends Record<string, StoreGetterThis> */,
+  G extends GettersTree<S>,
   A /* extends Record<string, StoreAction> */
 > {
   id: Id
index 5acd82585111a707ffc44b1e8b939aa33b724fa0..c2676e462f617891829173a7563c2e1c9b68b9e7 100644 (file)
@@ -4,7 +4,7 @@ const useDeprecated = createStore({
   id: 'name',
   state: () => ({ a: 'on' as 'on' | 'off', nested: { counter: 0 } }),
   getters: {
-    upper() {
+    upper(): string {
       return this.a.toUpperCase()
     },
   },
index 8b77999268e4e68c2f3efba8ef8d14bd2297b3bf..374bb4a0e1f26e3f1d0b1492e55f6e2d8ca906ce 100644 (file)
@@ -11,7 +11,7 @@ const useStore = defineStore({
   id: 'name',
   state: () => ({ a: 'on' as 'on' | 'off', nested: { counter: 0 } }),
   getters: {
-    upper() {
+    upper(): string {
       return this.a.toUpperCase()
     },
   },
index fcb4bee32f51ad6e8618849e65ad24fe90349174..cabd1f7f8bc70fd00759d2504334505512f7b634 100644 (file)
@@ -4,11 +4,15 @@ const useStore = defineStore({
   id: 'name',
   state: () => ({ a: 'on' as 'on' | 'off', nested: { counter: 0 } }),
   getters: {
-    upper() {
+    upper: (state) => {
+      expectType<'on' | 'off'>(state.a)
+      return state.a.toUpperCase() as 'ON' | 'OFF'
+    },
+    upperThis(): 'ON' | 'OFF' {
       expectType<'on' | 'off'>(this.a)
-      return this.a.toUpperCase()
+      return this.a.toUpperCase() as 'ON' | 'OFF'
     },
-    other() {
+    other(): false {
       expectType<string>(this.upper)
       return false
     },