From b7860a95b074bdbfc51a01d4574ad91f0cd7a2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Tue, 7 May 2019 11:36:03 +0200 Subject: [PATCH] [REF] store: typecheck code closes #87 closes #39 --- src/component.ts | 2 +- src/store.ts | 54 ++++++++++++++++++++++++----------------- tests/component.test.ts | 2 +- tests/store.test.ts | 2 +- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/component.ts b/src/component.ts index b76a41cb..d93a5cf7 100644 --- a/src/component.ts +++ b/src/component.ts @@ -11,7 +11,7 @@ export interface Env { qweb: QWeb; } -interface Meta { +export interface Meta { readonly id: number; vnode: VNode | null; isStarted: boolean; diff --git a/src/store.ts b/src/store.ts index 37ebf32a..73e5603a 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,4 +1,4 @@ -import { Component } from "./component"; +import { Component, Env } from "./component"; import { EventBus } from "./event_bus"; import { Observer } from "./observer"; @@ -6,11 +6,14 @@ import { Observer } from "./observer"; // Store Definition //------------------------------------------------------------------------------ +type Mutation = ({state, commit, set}, payload: any) => void; +type Action = ({commit, state, dispatch, env}, payload: any) => void; + interface StoreConfig { - env?: any; + env?: Env; state?: any; - actions?: any; - mutations?: { [name: string]: any }; + actions?: {[name: string]: Action}; + mutations?: { [name: string]: Mutation }; } interface StoreOption { @@ -46,7 +49,7 @@ export class Store extends EventBus { this.set = this.observer.set.bind(this.observer); } - dispatch(action, payload?: any): Promise | void { + dispatch(action: string, payload?: any): Promise | void { if (!this.actions[action]) { throw new Error(`[Error] action ${action} is undefined`); } @@ -67,7 +70,7 @@ export class Store extends EventBus { } } - commit(type, payload?: any) { + commit(type: string, payload?: any): any { if (!this.mutations[type]) { throw new Error(`[Error] mutation ${type} is undefined`); } @@ -117,6 +120,11 @@ function deepRevNumber(o: T): number { return 0; } +type Constructor = new (...args: any[]) => T; +interface EnvWithStore extends Env { + store: Store; +} + export function connect(mapStateToProps, options: any = {}) { let hashFunction = options.hashFunction || null; @@ -144,7 +152,9 @@ export function connect(mapStateToProps, options: any = {}) { }; } - return function(Comp) { + return function( + Comp: Constructor> + ) { return class extends Comp { constructor(parent, props?: any) { const env = parent instanceof Component ? parent.env : parent; @@ -152,9 +162,9 @@ export function connect(mapStateToProps, options: any = {}) { const storeProps = mapStateToProps(env.store.state, ownProps); const mergedProps = Object.assign({}, props || {}, storeProps); super(parent, mergedProps); - this.__owl__.ownProps = ownProps; - this.__owl__.currentStoreProps = storeProps; - this.__owl__.storeHash = hashFunction( + (this.__owl__).ownProps = ownProps; + (this.__owl__).currentStoreProps = storeProps; + (this.__owl__).storeHash = hashFunction( { state: env.store.state, storeProps: storeProps, @@ -181,10 +191,10 @@ export function connect(mapStateToProps, options: any = {}) { } _checkUpdate() { - const ownProps = this.__owl__.ownProps; + const ownProps = (this.__owl__).ownProps; const storeProps = mapStateToProps(this.env.store.state, ownProps); const options: any = { - currentStoreProps: this.__owl__.currentStoreProps + currentStoreProps: (this.__owl__).currentStoreProps }; const storeHash = hashFunction( { @@ -196,29 +206,29 @@ export function connect(mapStateToProps, options: any = {}) { options ); let didChange = options.didChange; - if (storeHash !== this.__owl__.storeHash) { + if (storeHash !== (this.__owl__).storeHash) { didChange = true; - this.__owl__.storeHash = storeHash; + (this.__owl__).storeHash = storeHash; } if (didChange) { - this.__owl__.currentStoreProps = storeProps; - this._updateProps(ownProps, false); + (this.__owl__).currentStoreProps = storeProps; + this._updateProps(ownProps, false, []); } } - _updateProps(nextProps, forceUpdate, p?: any) { - if (this.__owl__.ownProps !== nextProps) { - this.__owl__.currentStoreProps = mapStateToProps( + _updateProps(nextProps, forceUpdate, patchQueue: any[]) { + if ((this.__owl__).ownProps !== nextProps) { + (this.__owl__).currentStoreProps = mapStateToProps( this.env.store.state, nextProps ); } - this.__owl__.ownProps = nextProps; + (this.__owl__).ownProps = nextProps; const mergedProps = Object.assign( {}, nextProps, - this.__owl__.currentStoreProps + (this.__owl__).currentStoreProps ); - return super._updateProps(mergedProps, forceUpdate, p); + return super._updateProps(mergedProps, forceUpdate, patchQueue); } }; }; diff --git a/tests/component.test.ts b/tests/component.test.ts index 0a2185b4..246356b3 100644 --- a/tests/component.test.ts +++ b/tests/component.test.ts @@ -1646,7 +1646,7 @@ describe("async rendering", () => { ); }); - test.only("properly behave when destroyed/unmounted while rendering ", async () => { + test("properly behave when destroyed/unmounted while rendering ", async () => { let def = Promise.resolve(); class Child extends Widget { diff --git a/tests/store.test.ts b/tests/store.test.ts index 27305b20..49cb54d7 100644 --- a/tests/store.test.ts +++ b/tests/store.test.ts @@ -141,7 +141,7 @@ describe("basic use", () => { test("env is given to actions", () => { expect.assertions(1); - const someEnv = {}; + const someEnv = {}; const actions = { someaction({ env }) { expect(env).toBe(someEnv);