From: Eduardo San Martin Morote Date: Thu, 29 Apr 2021 14:21:17 +0000 (+0200) Subject: refactor(types): better getter types X-Git-Tag: v2.0.0-alpha.14~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6baf6ff9b6454712edf1607004be547d646dda1f;p=thirdparty%2Fvuejs%2Fpinia.git refactor(types): better getter types --- diff --git a/__tests__/getters.spec.ts b/__tests__/getters.spec.ts index 26d04f6f..28352989 100644 --- a/__tests__/getters.spec.ts +++ b/__tests__/getters.spec.ts @@ -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 }, diff --git a/__tests__/lifespan.spec.ts b/__tests__/lifespan.spec.ts index a299b346..aef85fb7 100644 --- a/__tests__/lifespan.spec.ts +++ b/__tests__/lifespan.spec.ts @@ -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 }, }, }) diff --git a/__tests__/mapHelpers.spec.ts b/__tests__/mapHelpers.spec.ts index cdd1f074..d917e446 100644 --- a/__tests__/mapHelpers.spec.ts +++ b/__tests__/mapHelpers.spec.ts @@ -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: { diff --git a/__tests__/pinia/stores/cart.ts b/__tests__/pinia/stores/cart.ts index 13aadf39..eca0d1f3 100644 --- a/__tests__/pinia/stores/cart.ts +++ b/__tests__/pinia/stores/cart.ts @@ -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) diff --git a/__tests__/pinia/stores/user.ts b/__tests__/pinia/stores/user.ts index 956fb1d4..64fab17e 100644 --- a/__tests__/pinia/stores/user.ts +++ b/__tests__/pinia/stores/user.ts @@ -31,8 +31,8 @@ export const useUserStore = defineStore({ }, }, getters: { - test() { - return this.name.toUpperCase() + test(state) { + return state.name.toUpperCase() }, }, }) diff --git a/__tests__/storePlugins.spec.ts b/__tests__/storePlugins.spec.ts index fde8ccf3..ef75b81e 100644 --- a/__tests__/storePlugins.spec.ts +++ b/__tests__/storePlugins.spec.ts @@ -24,9 +24,7 @@ describe('store plugins', () => { }, getters: { - doubleN() { - return this.n * 2 - }, + doubleN: (state) => state.n * 2, }, }) diff --git a/src/mapHelpers.ts b/src/mapHelpers.ts index eaa4d3c0..d7a9ac4c 100644 --- a/src/mapHelpers.ts +++ b/src/mapHelpers.ts @@ -1,6 +1,7 @@ import { ComponentInstance } from '@vue/devtools-api' import { GenericStore, + GettersTree, Method, StateTree, Store, @@ -48,7 +49,7 @@ type Spread = A extends [infer L, ...infer R] function getCachedStore< Id extends string = string, S extends StateTree = StateTree, - G = Record, + G extends GettersTree = GettersTree, A = Record >( vm: ComponentInstance, @@ -122,14 +123,14 @@ export function mapStores( }, {} as Spread) } -type MapStateReturn = { +type MapStateReturn> = { [key in keyof S | keyof G]: () => Store[key] } type MapStateObjectReturn< Id extends string, S extends StateTree, - G, + G extends GettersTree, A, T extends Record< string, @@ -182,7 +183,7 @@ type MapStateObjectReturn< export function mapState< Id extends string, S extends StateTree, - G, + G extends GettersTree, 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( +export function mapState< + Id extends string, + S extends StateTree, + G extends GettersTree, + A +>( useStore: StoreDefinition, keys: Array ): MapStateReturn @@ -230,7 +236,7 @@ export function mapState( export function mapState< Id extends string, S extends StateTree, - G, + G extends GettersTree, A, KeyMapper extends Record< string, @@ -303,7 +309,7 @@ type MapActionsObjectReturn> = { export function mapActions< Id extends string, S extends StateTree, - G, + G extends GettersTree, A, KeyMapper extends Record >( @@ -333,7 +339,12 @@ export function mapActions< * @param useStore - store to map from * @param keys - array of action names to map */ -export function mapActions( +export function mapActions< + Id extends string, + S extends StateTree, + G extends GettersTree, + A +>( useStore: StoreDefinition, keys: Array ): MapActionsReturn @@ -348,7 +359,7 @@ export function mapActions( export function mapActions< Id extends string, S extends StateTree, - G, + G extends GettersTree, A, KeyMapper extends Record >( @@ -398,7 +409,7 @@ type MapWritableStateObjectReturn< export function mapWritableState< Id extends string, S extends StateTree, - G, + G extends GettersTree, A, KeyMapper extends Record >( @@ -413,7 +424,12 @@ export function mapWritableState< * @param useStore - store to map from * @param keys - array of state properties */ -export function mapWritableState( +export function mapWritableState< + Id extends string, + S extends StateTree, + G extends GettersTree, + A +>( useStore: StoreDefinition, keys: Array ): MapWritableStateReturn @@ -428,7 +444,7 @@ export function mapWritableState( export function mapWritableState< Id extends string, S extends StateTree, - G, + G extends GettersTree, A, KeyMapper extends Record >( diff --git a/src/rootStore.ts b/src/rootStore.ts index dd4f1c22..c3b601f2 100644 --- a/src/rootStore.ts +++ b/src/rootStore.ts @@ -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, + G extends GettersTree = GettersTree, A = Record > { /** diff --git a/src/store.ts b/src/store.ts index fe96a924..02584087 100644 --- a/src/store.ts +++ b/src/store.ts @@ -23,6 +23,7 @@ import { DefineStoreOptions, StoreDefinition, GenericStore, + GettersTree, } from './types' import { getActivePinia, @@ -215,7 +216,7 @@ function initStore( function buildStoreToUse< Id extends string, S extends StateTree, - G extends Record, + G extends GettersTree, A extends Record >( partialStore: StoreWithState, @@ -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[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 */, + G extends GettersTree, A /* extends Record */ >(options: DefineStoreOptions): StoreDefinition { const { id, state, getters, actions } = options @@ -314,7 +316,7 @@ export function defineStore< storeAndDescriptor[0], storeAndDescriptor[1], id, - getters as Record | undefined, + getters as GettersTree | undefined, actions as Record | 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 | undefined, + getters as GettersTree | undefined, actions as Record | undefined, // @ts-ignore: because we don't have extend on G and A options diff --git a/src/types.ts b/src/types.ts index bd1ed9ad..6163b00e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -144,7 +144,7 @@ export type StoreWithGetters = { export type Store< Id extends string, S extends StateTree, - G, + G extends GettersTree, // has the actions without the context (this) for typings A > = StoreWithState & @@ -153,13 +153,15 @@ export type Store< StoreWithActions & PiniaCustomProperties +// 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 */, + G extends GettersTree, A /* extends Record */ > { (pinia?: Pinia | null | undefined): Store @@ -172,7 +174,7 @@ export interface StoreDefinition< export type GenericStore = Store< string, StateTree, - Record, + GettersTree, Record > @@ -182,7 +184,7 @@ export type GenericStore = Store< export type GenericStoreDefinition = StoreDefinition< string, StateTree, - Record, + GettersTree, Record > @@ -192,10 +194,15 @@ export type GenericStoreDefinition = StoreDefinition< export interface PiniaCustomProperties< Id extends string = string, S extends StateTree = StateTree, - G = Record, + G extends GettersTree = GettersTree, A = Record > {} +export type GettersTree = 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 */, + G extends GettersTree, A /* extends Record */ > { id: Id diff --git a/test-dts/deprecated.test-d.ts b/test-dts/deprecated.test-d.ts index 5acd8258..c2676e46 100644 --- a/test-dts/deprecated.test-d.ts +++ b/test-dts/deprecated.test-d.ts @@ -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() }, }, diff --git a/test-dts/mapHelpers.test-d.ts b/test-dts/mapHelpers.test-d.ts index 8b779992..374bb4a0 100644 --- a/test-dts/mapHelpers.test-d.ts +++ b/test-dts/mapHelpers.test-d.ts @@ -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() }, }, diff --git a/test-dts/store.test-d.ts b/test-dts/store.test-d.ts index fcb4bee3..cabd1f7f 100644 --- a/test-dts/store.test-d.ts +++ b/test-dts/store.test-d.ts @@ -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(this.upper) return false },