From 2ee058ef0264dddb367c53ce534f832bdb7b5fb0 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Thu, 24 Jun 2021 12:04:47 +0200 Subject: [PATCH] fix(types): forbid non existant access in getters and actions --- src/store.ts | 8 ++--- src/types.ts | 24 ++++++++++---- test-dts/store.test-d.ts | 72 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 92 insertions(+), 12 deletions(-) diff --git a/src/store.ts b/src/store.ts index 10170169..55017eb5 100644 --- a/src/store.ts +++ b/src/store.ts @@ -413,10 +413,10 @@ export function defineStore< if (pinia) setActivePinia(pinia) // TODO: worth warning on server if no piniaKey as it can leak data pinia = getActivePinia() - let stores = storesMap.get(pinia) - if (!stores) storesMap.set(pinia, (stores = new Map())) + let storeCache = storesMap.get(pinia) + if (!storeCache) storesMap.set(pinia, (storeCache = new Map())) - let storeAndDescriptor = stores.get(id) as + let storeAndDescriptor = storeCache.get(id) as | [ StoreWithState, StateDescriptor, @@ -430,7 +430,7 @@ export function defineStore< storeAndDescriptor = initStore(id, state, pinia.state.value[id]) // @ts-expect-error: annoying to type - stores.set(id, storeAndDescriptor) + storeCache.set(id, storeAndDescriptor) store = buildStoreToUse< Id, diff --git a/src/types.ts b/src/types.ts index 7c29becd..0141e571 100644 --- a/src/types.ts +++ b/src/types.ts @@ -226,7 +226,8 @@ export interface StoreWithState< /** * State of the Store. Setting it will replace the whole state. */ - $state: UnwrapRef & PiniaCustomStateProperties + $state: UnwrapRef & + PiniaCustomStateProperties /** * Private property defining the pinia the store is attached to. @@ -387,7 +388,7 @@ export type Store< */ export type GenericStore< Id extends string = string, - S extends StateTree = StateTree, + S extends StateTree = any, G extends GettersTree = GettersTree, // has the actions without the context (this) for typings A /* extends ActionsTree */ = ActionsTree @@ -442,7 +443,12 @@ export interface PiniaCustomStateProperties {} */ export type GettersTree = Record< string, - ((state: UnwrapRef>) => any) | (() => any) + | (( + state: UnwrapRef< + (StateTree extends S ? {} : S) & PiniaCustomStateProperties + > + ) => any) + | (() => any) > /** @@ -466,24 +472,30 @@ export interface DefineStoreOptions< * Unique string key to identify the store across the application. */ id: Id + /** * Function to create a fresh state. */ state?: () => S + /** * Optional object of getters. */ getters?: G & - ThisType & StoreWithGetters & PiniaCustomProperties> + ThisType< + UnwrapRef & + StoreWithGetters & + PiniaCustomProperties + > /** * Optional object of actions. */ actions?: A & ThisType< A & - UnwrapRef & + UnwrapRef & StoreWithState & - StoreWithGetters & + StoreWithGetters extends G ? {} : G> & PiniaCustomProperties > } diff --git a/test-dts/store.test-d.ts b/test-dts/store.test-d.ts index 436dfdb6..ec81dc16 100644 --- a/test-dts/store.test-d.ts +++ b/test-dts/store.test-d.ts @@ -25,6 +25,8 @@ const useStore = defineStore({ }, actions: { doStuff() { + // @ts-expect-error + this.notExisting expectType(this.upper) expectType(this.other) }, @@ -34,6 +36,73 @@ const useStore = defineStore({ }, }) +// actions on not existing properties +defineStore({ + id: '', + actions: { + a() { + // @ts-expect-error + this.notExisting + }, + }, +}) + +defineStore({ + id: '', + state: () => ({}), + actions: { + a() { + // @ts-expect-error + this.notExisting + }, + }, +}) + +defineStore({ + id: '', + getters: {}, + actions: { + a() { + // @ts-expect-error + this.notExisting + }, + }, +}) + +// getters on not existing properties +defineStore({ + id: '', + getters: { + a(): number { + // @ts-expect-error + this.notExisting + return 2 + }, + b: (state) => { + // @ts-expect-error + state.notExisting + return + }, + }, +}) + +defineStore({ + id: '', + state: () => ({}), + getters: { + a(): number { + // @ts-expect-error + this.notExisting + return 2 + }, + b: (state) => { + // @ts-expect-error + state.notExisting + return + }, + }, +}) + const store = useStore() expectType<{ a: 'on' | 'off' }>(store.$state) @@ -169,6 +238,5 @@ expectType(genericStore.thing) expectType(genericStore.$state.thing) takeStore(genericStore) useSyncValueToStore(() => 2, genericStore, 'myState') -useSyncValueToStore(() => 2, genericStore, 'random') -// @ts-expect-error useSyncValueToStore(() => false, genericStore, 'myState') +useSyncValueToStore(() => 2, genericStore, 'random') -- 2.47.2