[REF] store: typecheck code

closes #87
closes #39
This commit is contained in:
Géry Debongnie
2019-05-07 11:36:03 +02:00
parent f7495dc897
commit b7860a95b0
4 changed files with 35 additions and 25 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ export interface Env {
qweb: QWeb; qweb: QWeb;
} }
interface Meta<T extends Env, Props> { export interface Meta<T extends Env, Props> {
readonly id: number; readonly id: number;
vnode: VNode | null; vnode: VNode | null;
isStarted: boolean; isStarted: boolean;
+32 -22
View File
@@ -1,4 +1,4 @@
import { Component } from "./component"; import { Component, Env } from "./component";
import { EventBus } from "./event_bus"; import { EventBus } from "./event_bus";
import { Observer } from "./observer"; import { Observer } from "./observer";
@@ -6,11 +6,14 @@ import { Observer } from "./observer";
// Store Definition // Store Definition
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
type Mutation = ({state, commit, set}, payload: any) => void;
type Action = ({commit, state, dispatch, env}, payload: any) => void;
interface StoreConfig { interface StoreConfig {
env?: any; env?: Env;
state?: any; state?: any;
actions?: any; actions?: {[name: string]: Action};
mutations?: { [name: string]: any }; mutations?: { [name: string]: Mutation };
} }
interface StoreOption { interface StoreOption {
@@ -46,7 +49,7 @@ export class Store extends EventBus {
this.set = this.observer.set.bind(this.observer); this.set = this.observer.set.bind(this.observer);
} }
dispatch(action, payload?: any): Promise<void> | void { dispatch(action: string, payload?: any): Promise<void> | void {
if (!this.actions[action]) { if (!this.actions[action]) {
throw new Error(`[Error] action ${action} is undefined`); 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]) { if (!this.mutations[type]) {
throw new Error(`[Error] mutation ${type} is undefined`); throw new Error(`[Error] mutation ${type} is undefined`);
} }
@@ -117,6 +120,11 @@ function deepRevNumber<T extends Object>(o: T): number {
return 0; return 0;
} }
type Constructor<T> = new (...args: any[]) => T;
interface EnvWithStore extends Env {
store: Store;
}
export function connect(mapStateToProps, options: any = {}) { export function connect(mapStateToProps, options: any = {}) {
let hashFunction = options.hashFunction || null; let hashFunction = options.hashFunction || null;
@@ -144,7 +152,9 @@ export function connect(mapStateToProps, options: any = {}) {
}; };
} }
return function(Comp) { return function<E extends EnvWithStore, P, S>(
Comp: Constructor<Component<E, P, S>>
) {
return class extends Comp { return class extends Comp {
constructor(parent, props?: any) { constructor(parent, props?: any) {
const env = parent instanceof Component ? parent.env : parent; 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 storeProps = mapStateToProps(env.store.state, ownProps);
const mergedProps = Object.assign({}, props || {}, storeProps); const mergedProps = Object.assign({}, props || {}, storeProps);
super(parent, mergedProps); super(parent, mergedProps);
this.__owl__.ownProps = ownProps; (<any>this.__owl__).ownProps = ownProps;
this.__owl__.currentStoreProps = storeProps; (<any>this.__owl__).currentStoreProps = storeProps;
this.__owl__.storeHash = hashFunction( (<any>this.__owl__).storeHash = hashFunction(
{ {
state: env.store.state, state: env.store.state,
storeProps: storeProps, storeProps: storeProps,
@@ -181,10 +191,10 @@ export function connect(mapStateToProps, options: any = {}) {
} }
_checkUpdate() { _checkUpdate() {
const ownProps = this.__owl__.ownProps; const ownProps = (<any>this.__owl__).ownProps;
const storeProps = mapStateToProps(this.env.store.state, ownProps); const storeProps = mapStateToProps(this.env.store.state, ownProps);
const options: any = { const options: any = {
currentStoreProps: this.__owl__.currentStoreProps currentStoreProps: (<any>this.__owl__).currentStoreProps
}; };
const storeHash = hashFunction( const storeHash = hashFunction(
{ {
@@ -196,29 +206,29 @@ export function connect(mapStateToProps, options: any = {}) {
options options
); );
let didChange = options.didChange; let didChange = options.didChange;
if (storeHash !== this.__owl__.storeHash) { if (storeHash !== (<any>this.__owl__).storeHash) {
didChange = true; didChange = true;
this.__owl__.storeHash = storeHash; (<any>this.__owl__).storeHash = storeHash;
} }
if (didChange) { if (didChange) {
this.__owl__.currentStoreProps = storeProps; (<any>this.__owl__).currentStoreProps = storeProps;
this._updateProps(ownProps, false); this._updateProps(ownProps, false, []);
} }
} }
_updateProps(nextProps, forceUpdate, p?: any) { _updateProps(nextProps, forceUpdate, patchQueue: any[]) {
if (this.__owl__.ownProps !== nextProps) { if ((<any>this.__owl__).ownProps !== nextProps) {
this.__owl__.currentStoreProps = mapStateToProps( (<any>this.__owl__).currentStoreProps = mapStateToProps(
this.env.store.state, this.env.store.state,
nextProps nextProps
); );
} }
this.__owl__.ownProps = nextProps; (<any>this.__owl__).ownProps = nextProps;
const mergedProps = Object.assign( const mergedProps = Object.assign(
{}, {},
nextProps, nextProps,
this.__owl__.currentStoreProps (<any>this.__owl__).currentStoreProps
); );
return super._updateProps(mergedProps, forceUpdate, p); return super._updateProps(mergedProps, forceUpdate, patchQueue);
} }
}; };
}; };
+1 -1
View File
@@ -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(); let def = Promise.resolve();
class Child extends Widget { class Child extends Widget {
+1 -1
View File
@@ -141,7 +141,7 @@ describe("basic use", () => {
test("env is given to actions", () => { test("env is given to actions", () => {
expect.assertions(1); expect.assertions(1);
const someEnv = {}; const someEnv = <Env>{};
const actions = { const actions = {
someaction({ env }) { someaction({ env }) {
expect(env).toBe(someEnv); expect(env).toBe(someEnv);