mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] types: do not make Env an indexed type
Before this commit, Env was an indexed type, this means that one could
write env.anything, and it would accept it as a valid type. This is
actually quite dangerous, because we lose the typing advantages for all
keys that are properly defined.
For example, if a component is defined as:
class MyComponent extends Component<Props> {
...
}
Then Typescript will let it use anything from the environment, even if
it is wrong. So, most properly typed Typescript applications should use
instead a sub environment:
interface MyAppEnv extends Env {
someKey: someValue
}
Then, the component should be defined this way:
class MyComponent extends Component<Props, MyAppEnv> {
...
}
Before this commit, any typos in the environment accesses would not be
noticed by typescript.
This commit is contained in:
@@ -34,7 +34,6 @@ import { activateSheet } from "./styles";
|
||||
*/
|
||||
export interface Env {
|
||||
qweb: QWeb;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type MountPosition = "first-child" | "last-child" | "self";
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Component } from "../component/component";
|
||||
import { xml } from "../tags";
|
||||
import { EnvWithRouter } from "./router";
|
||||
|
||||
export class RouteComponent extends Component {
|
||||
export class RouteComponent extends Component<{}, EnvWithRouter> {
|
||||
static template = xml`
|
||||
<t>
|
||||
<t
|
||||
|
||||
@@ -49,6 +49,10 @@ interface Options {
|
||||
mode: Router["mode"];
|
||||
}
|
||||
|
||||
export interface EnvWithRouter extends Env {
|
||||
router: Router;
|
||||
}
|
||||
|
||||
const paramRegexp = /\{\{(.*?)\}\}/;
|
||||
|
||||
export class Router {
|
||||
@@ -60,7 +64,11 @@ export class Router {
|
||||
routeIds: string[];
|
||||
env: RouterEnv;
|
||||
|
||||
constructor(env: Env, routes: Partial<Route>[], options: Options = { mode: "history" }) {
|
||||
constructor(
|
||||
env: Partial<EnvWithRouter>,
|
||||
routes: Partial<Route>[],
|
||||
options: Options = { mode: "history" }
|
||||
) {
|
||||
env.router = this;
|
||||
this.mode = options.mode;
|
||||
this.env = env as RouterEnv;
|
||||
|
||||
+7
-3
@@ -24,6 +24,10 @@ import { onWillUpdateProps } from "./hooks";
|
||||
// Store Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
export interface EnvWithStore extends Env {
|
||||
store: Store;
|
||||
}
|
||||
|
||||
export type Action = ({ state, dispatch, env, getters }, ...payload: any) => any;
|
||||
export type Getter = ({ state: any, getters }, payload?) => any;
|
||||
|
||||
@@ -83,7 +87,7 @@ interface SelectorOptions {
|
||||
const isStrictEqual = (a, b) => a === b;
|
||||
|
||||
export function useStore(selector, options: SelectorOptions = {}): any {
|
||||
const component: Component = Component.current!;
|
||||
const component = Component.current as Component<any, EnvWithStore>;
|
||||
const componentId = component.__owl__.id;
|
||||
const store = options.store || (component.env.store as Store);
|
||||
if (!(store instanceof Store)) {
|
||||
@@ -149,11 +153,11 @@ export function useStore(selector, options: SelectorOptions = {}): any {
|
||||
}
|
||||
|
||||
export function useDispatch(store?: Store): Store["dispatch"] {
|
||||
store = store || (Component.current!.env.store as Store);
|
||||
store = store || (Component.current!.env as EnvWithStore).store;
|
||||
return store.dispatch.bind(store);
|
||||
}
|
||||
|
||||
export function useGetters(store?: Store): Store["getters"] {
|
||||
store = store || (Component.current!.env.store as Store);
|
||||
store = store || (Component.current!.env as EnvWithStore).store;
|
||||
return store.getters;
|
||||
}
|
||||
|
||||
@@ -3484,11 +3484,14 @@ describe("environment and plugins", () => {
|
||||
});
|
||||
|
||||
test("can define specific env for root components", async () => {
|
||||
class App1 extends Component {
|
||||
interface AppEnv extends Env {
|
||||
test: number;
|
||||
}
|
||||
class App1 extends Component<{}, AppEnv> {
|
||||
static template = xml`<span></span>`;
|
||||
}
|
||||
App1.env = { test: 1 };
|
||||
class App2 extends Component {
|
||||
class App2 extends Component<{}, AppEnv> {
|
||||
static template = xml`<span></span>`;
|
||||
}
|
||||
App2.env = { test: 2 };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, Env } from "../src/component/component";
|
||||
import { Store, useStore, useDispatch, useGetters } from "../src/store";
|
||||
import { Store, useStore, useDispatch, useGetters, EnvWithStore } from "../src/store";
|
||||
import { useState } from "../src/hooks";
|
||||
import { xml } from "../src/tags";
|
||||
import { shallowEqual } from "../src/utils";
|
||||
@@ -885,7 +885,7 @@ describe("connecting a component to store", () => {
|
||||
actions
|
||||
});
|
||||
|
||||
class TodoItem extends Component {
|
||||
class TodoItem extends Component<{}, EnvWithStore> {
|
||||
static template = xml`
|
||||
<div class="todo">
|
||||
<t t-esc="state.todo.title"/>
|
||||
@@ -958,7 +958,7 @@ describe("connecting a component to store", () => {
|
||||
actions
|
||||
});
|
||||
|
||||
class TodoItem extends Component {
|
||||
class TodoItem extends Component<{}, EnvWithStore> {
|
||||
static template = xml`
|
||||
<div class="todo">
|
||||
<t t-esc="state.todo.title"/>
|
||||
|
||||
Reference in New Issue
Block a user