From: Richard Banks Date: Wed, 29 Sep 2021 10:12:17 +0000 (+1000) Subject: feat(warn): incorrect state value #641 (#646) X-Git-Tag: pinia@2.0.0-rc.10~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6fd3883100ccc5c11668c3b855ff0660dd8af9fe;p=thirdparty%2Fvuejs%2Fpinia.git feat(warn): incorrect state value #641 (#646) * docs: Add notes on mapState and undefined properties. #641 * feat: warn when constructor call detected in state initialization function * refactor: revise regex used to detect constructor calls * feat: warn when a class is used to intialize store state * feat: warn when a class is used to intialize store state * feat: warn when a class is used to intialize store state * Apply suggestions from code review Co-authored-by: Eduardo San Martin Morote --- diff --git a/packages/pinia/__tests__/store.spec.ts b/packages/pinia/__tests__/store.spec.ts index 82592688..88cbe4b9 100644 --- a/packages/pinia/__tests__/store.spec.ts +++ b/packages/pinia/__tests__/store.spec.ts @@ -1,8 +1,11 @@ import { createPinia, defineStore, setActivePinia } from '../src' import { mount } from '@vue/test-utils' import { defineComponent, getCurrentInstance, nextTick, watch } from 'vue' +import { mockWarn } from 'jest-mock-warn' describe('Store', () => { + mockWarn() + beforeEach(() => { setActivePinia(createPinia()) }) @@ -330,4 +333,34 @@ describe('Store', () => { expect(useStore()).not.toBe(store) }) + + it('warns when state is created with a class constructor', () => { + class MyState {} + + const useMyStore = defineStore({ + id: 'store', + state: () => new MyState(), + }) + useMyStore() + expect('Detected constructor usage').toHaveBeenWarned() + }) + + it('only warns about constructors when store is initially created', () => { + class MyState {} + const useMyStore = defineStore({ + id: 'arrowInit', + state: () => new MyState(), + }); + useMyStore() + expect('Detected constructor usage').toHaveBeenWarnedTimes(1) + }) + + it('does not warn when state is created with a plain object', () => { + const useMyStore = defineStore({ + id: 'poInit', + state: () => ({ someValue: undefined }) + }) + useMyStore() + expect('Detected constructor usage').toHaveBeenWarnedTimes(0) + }) }) diff --git a/packages/pinia/src/store.ts b/packages/pinia/src/store.ts index 1082d91b..f4f10e29 100644 --- a/packages/pinia/src/store.ts +++ b/packages/pinia/src/store.ts @@ -673,6 +673,18 @@ function createSetupStore< } }) + if ( + __DEV__ && + store.$state && + typeof store.$state === 'object' && + typeof store.$state.constructor === 'function' && + !store.$state.constructor.toString().includes('[native code]') + ) { + console.warn( + `[🍍]: The "state" must be a plain object. It cannot be\n\tstate: () => new MyClass()` + ) + } + // only apply hydrate to option stores with an initial state in pinia if (initialState && buildState) { ;(options.hydrate || innerPatch)(store, initialState)