[IMP] types: make component generic types optional

In most cases, we just want Component<any, Env>. But since it was so
annoying to have always the type Env, we actually used
Component<any,any> everywhere.

With this commit, the generic types have a default (and their order is
swapped), so we can simply use Component in most cases, and
Component<Props> when we want to type the props.
This commit is contained in:
Géry Debongnie
2020-02-05 21:30:14 +01:00
committed by aab-odoo
parent d212309f1b
commit 3fdc7a48f3
33 changed files with 700 additions and 711 deletions
+10 -10
View File
@@ -46,7 +46,7 @@ interface MountOptions {
* useful to typecheck and describe the internal keys used by Owl to manage the
* component tree.
*/
interface Internal<T extends Env, Props> {
interface Internal<T extends Env> {
// each component has a unique id, useful mostly to handle parent/child
// relationships
readonly id: number;
@@ -58,8 +58,8 @@ interface Internal<T extends Env, Props> {
// parent and children keys are obviously useful to setup the parent-children
// relationship.
parent: Component<T, any> | null;
children: { [key: number]: Component<T, any> };
parent: Component<any, T> | null;
children: { [key: number]: Component<any, T> };
// children mapping: from templateID to componentID. templateID identifies a
// place in a template. The t-component directive needs it to be able to get
// the component instance back whenever the template is rerendered.
@@ -85,7 +85,7 @@ interface Internal<T extends Env, Props> {
willStartCB: Function | null;
willUpdatePropsCB: Function | null;
classObj: { [key: string]: boolean } | null;
refs: { [key: string]: Component<T, any> | HTMLElement | undefined } | null;
refs: { [key: string]: Component<any, T> | HTMLElement | undefined } | null;
}
export const portalSymbol = Symbol("portal"); // FIXME
@@ -95,11 +95,11 @@ export const portalSymbol = Symbol("portal"); // FIXME
//------------------------------------------------------------------------------
let nextId = 1;
export class Component<T extends Env, Props extends {}> {
readonly __owl__: Internal<Env, Props>;
export class Component<Props extends {} = any, T extends Env = Env> {
readonly __owl__: Internal<T>;
static template?: string | null = null;
static _template?: string | null = null;
static current: Component<any, any> | null = null;
static current: Component | null = null;
static components = {};
static props?: any;
static defaultProps?: any;
@@ -130,7 +130,7 @@ export class Component<T extends Env, Props extends {}> {
* hand. Other components should be created automatically by the framework (with
* the t-component directive in a template)
*/
constructor(parent?: Component<T, any> | null, props?: Props) {
constructor(parent?: Component<any, T> | null, props?: Props) {
Component.current = this;
let constr = this.constructor as any;
@@ -441,7 +441,7 @@ export class Component<T extends Env, Props extends {}> {
* Note that it does not call the __callWillUnmount method to avoid visiting
* all children many times.
*/
__destroy(parent: Component<any, any> | null) {
__destroy(parent: Component | null) {
const __owl__ = this.__owl__;
const isMounted = __owl__.isMounted;
if (isMounted) {
@@ -501,7 +501,7 @@ export class Component<T extends Env, Props extends {}> {
* Private trigger method, allows to choose the component which triggered
* the event in the first place
*/
__trigger(component: Component<any, any>, eventType: string, payload?: any) {
__trigger(component: Component, eventType: string, payload?: any) {
if (this.el) {
const ev = new OwlEvent(component, eventType, {
bubbles: true,
+2 -2
View File
@@ -50,7 +50,7 @@ export class Fiber {
scope: any;
component: Component<any, any>;
component: Component;
vnode: VNode | null = null;
root: Fiber;
@@ -61,7 +61,7 @@ export class Fiber {
error?: Error;
constructor(parent: Fiber | null, component: Component<any, any>, force, inserter) {
constructor(parent: Fiber | null, component: Component, force: boolean, inserter) {
this.component = component;
this.force = force;
this.inserter = inserter;
+2 -2
View File
@@ -100,11 +100,11 @@ export class Context extends EventBus {
* to context state changes. The `useContext` method returns the context state
*/
export function useContext(ctx: Context): any {
const component: Component<any, any> = Component.current!;
const component: Component = Component.current!;
return useContextWithCB(ctx, component, component.render.bind(component));
}
export function useContextWithCB(ctx: Context, component: Component<any, any>, method): any {
export function useContextWithCB(ctx: Context, component: Component, method): any {
const __owl__ = component.__owl__;
const id = __owl__.id;
const mapping = ctx.mapping;
+1 -1
View File
@@ -7,7 +7,7 @@ import { Component } from "../component/component";
*/
export class OwlEvent<T> extends CustomEvent<T> {
originalComponent: Component<any, any>;
originalComponent: Component;
constructor(component, eventType, options) {
super(eventType, options);
this.originalComponent = component;
+6 -6
View File
@@ -22,7 +22,7 @@ import { Observer } from "./core/observer";
* trigger a rerendering of the current component.
*/
export function useState<T>(state: T): T {
const component: Component<any, any> = Component.current!;
const component: Component = Component.current!;
const __owl__ = component.__owl__;
if (!__owl__.observer) {
__owl__.observer = new Observer();
@@ -37,7 +37,7 @@ export function useState<T>(state: T): T {
function makeLifecycleHook(method: string, reverse: boolean = false) {
if (reverse) {
return function(cb) {
const component: Component<any, any> = Component.current!;
const component: Component = Component.current!;
if (component.__owl__[method]) {
const current = component.__owl__[method];
component.__owl__[method] = function() {
@@ -50,7 +50,7 @@ function makeLifecycleHook(method: string, reverse: boolean = false) {
};
} else {
return function(cb) {
const component: Component<any, any> = Component.current!;
const component: Component = Component.current!;
if (component.__owl__[method]) {
const current = component.__owl__[method];
component.__owl__[method] = function() {
@@ -66,7 +66,7 @@ function makeLifecycleHook(method: string, reverse: boolean = false) {
function makeAsyncHook(method: string) {
return function(cb) {
const component: Component<any, any> = Component.current!;
const component: Component = Component.current!;
if (component.__owl__[method]) {
const current = component.__owl__[method];
component.__owl__[method] = function(...args) {
@@ -96,7 +96,7 @@ export const onWillUpdateProps = makeAsyncHook("willUpdatePropsCB");
*/
interface Ref {
el: HTMLElement | null;
comp: Component<any, any> | null;
comp: Component | null;
}
export function useRef(name: string): Ref {
@@ -111,7 +111,7 @@ export function useRef(name: string): Ref {
}
return null;
},
get comp(): Component<any, any> | null {
get comp(): Component | null {
const val = __owl__.refs && __owl__.refs[name];
return val instanceof Component ? val : null;
}
+1 -1
View File
@@ -10,7 +10,7 @@ import { xml } from "../tags";
* from this coordination. This is the goal of the AsyncRoot component.
*/
export class AsyncRoot extends Component<any, any> {
export class AsyncRoot extends Component {
static template = xml`<t t-slot="default"/>`;
async __updateProps(nextProps, parentFiber) {
+7 -3
View File
@@ -18,7 +18,11 @@ import { useSubEnv } from "../hooks";
* are re-triggered on an empty <portal> node located in the parent's DOM.
*/
export class Portal extends Component<any, any> {
interface Props {
target: string;
}
export class Portal extends Component<Props> {
static template = xml`<portal><t t-slot="default"/></portal>`;
static props = {
target: {
@@ -43,7 +47,7 @@ export class Portal extends Component<any, any> {
// represents the element that is moved somewhere else
portal: VNode | null = null;
// the target where we will move `portal`
target: HTMLElement | null = null;
target: Element | null = null;
constructor(parent, props) {
super(parent, props);
@@ -158,7 +162,7 @@ export class Portal extends Component<any, any> {
/**
* Override to set the env
*/
__trigger(component: Component<any, any>, eventType: string, payload?: any) {
__trigger(component: Component, eventType: string, payload?: any) {
const env = this.env;
this.env = this.parentEnv;
super.__trigger(component, eventType, payload);
+1 -1
View File
@@ -4,7 +4,7 @@ import { Destination, RouterEnv } from "./router";
type Props = Destination;
export class Link<Env extends RouterEnv> extends Component<Env, Props> {
export class Link<Env extends RouterEnv> extends Component<Props, Env> {
static template = xml`
<a t-att-class="{'router-link-active': isActive }"
t-att-href="href"
+1 -1
View File
@@ -1,7 +1,7 @@
import { Component } from "../component/component";
import { xml } from "../tags";
export class RouteComponent extends Component<any, {}> {
export class RouteComponent extends Component {
static template = xml`
<t>
<t
+1 -1
View File
@@ -83,7 +83,7 @@ interface SelectorOptions {
const isStrictEqual = (a, b) => a === b;
export function useStore(selector, options: SelectorOptions = {}): any {
const component: Component<any, any> = Component.current!;
const component: Component = Component.current!;
const componentId = component.__owl__.id;
const store = options.store || (component.env.store as Store);
if (!(store instanceof Store)) {