Merge pull request #31825 from spacejack/mithril-closurecomponent

Mithril - Add ClosureComponent type alias
This commit is contained in:
Sheetal Nandi
2019-01-02 11:54:20 -08:00
committed by GitHub
4 changed files with 54 additions and 13 deletions
+13 -6
View File
@@ -173,7 +173,7 @@ declare namespace Mithril {
type ChildArrayOrPrimitive = ChildArray | string | number | boolean;
/** Virtual DOM nodes, or vnodes, are Javascript objects that represent an element (or parts of the DOM). */
interface Vnode<Attrs = {}, State extends Lifecycle<Attrs, State> = Lifecycle<Attrs, State>> {
interface Vnode<Attrs = {}, State extends Lifecycle<Attrs, State> = {}> {
/** The nodeName of a DOM element. It may also be the string [ if a vnode is a fragment, # if it's a text vnode, or < if it's a trusted HTML vnode. Additionally, it may be a component. */
tag: string | ComponentTypes<Attrs, State>;
/** A hashmap of DOM attributes, events, properties and lifecycle methods. */
@@ -194,7 +194,7 @@ declare namespace Mithril {
// In some lifecycle methods, Vnode will have a dom property
// and possibly a domSize property.
interface VnodeDOM<Attrs = {}, State extends Lifecycle<Attrs, State> = Lifecycle<Attrs, State>> extends Vnode<Attrs, State> {
interface VnodeDOM<Attrs = {}, State extends Lifecycle<Attrs, State> = {}> extends Vnode<Attrs, State> {
/** Points to the element that corresponds to the vnode. */
dom: Element;
/** This defines the number of DOM elements that the vnode represents (starting from the element referenced by the dom property). */
@@ -210,7 +210,7 @@ declare namespace Mithril {
* Any Javascript object that has a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
interface Component<Attrs = {}, State extends Lifecycle<Attrs, State> = Lifecycle<Attrs, State>> extends Lifecycle<Attrs, State> {
interface Component<Attrs = {}, State extends Lifecycle<Attrs, State> = {}> extends Lifecycle<Attrs, State> {
/** Creates a view out of virtual elements. */
view(this: State, vnode: Vnode<Attrs, State>): Children | null | void;
}
@@ -242,16 +242,23 @@ declare namespace Mithril {
* Any function that returns an object with a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
type FactoryComponent<A = {}> = (vnode: Vnode<A, {}>) => Component<A, {}>;
type FactoryComponent<A = {}> = (vnode: Vnode<A>) => Component<A>;
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any function that returns an object with a view method can be used as a Mithril component.
* Components can be consumed via the m() utility.
*/
type ClosureComponent<A = {}> = FactoryComponent<A>;
/**
* Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse.
* Any Javascript object that has a view method is a Mithril component. Components can be consumed via the m() utility.
*/
type Comp<Attrs = {}, State extends Lifecycle<Attrs, State> = Lifecycle<Attrs, State>> = Component<Attrs, State> & State;
type Comp<Attrs = {}, State extends Lifecycle<Attrs, State> = {}> = Component<Attrs, State> & State;
/** Components are a mechanism to encapsulate parts of a view to make code easier to organize and/or reuse. Components can be consumed via the m() utility. */
type ComponentTypes<A = {}, S extends Lifecycle<A, S> = Lifecycle<A, S>> = Component<A, S> | { new (vnode: CVnode<A>): ClassComponent<A> } | FactoryComponent<A>;
type ComponentTypes<A = {}, S extends Lifecycle<A, S> = {}> = Component<A, S> | { new (vnode: CVnode<A>): ClassComponent<A> } | FactoryComponent<A>;
/** This represents the attributes available for configuring virtual elements, beyond the applicable DOM attributes. */
interface Attributes extends Lifecycle<any, any> {
+4 -4
View File
@@ -116,7 +116,7 @@ const FRAME_BUDGET = 100;
{
// define a component
const Greeter: m.Comp<{ style: string }, {}> = {
const Greeter: m.Comp<{ style: string }> = {
view(vnode) {
return m("div", vnode.attrs, ["Hello ", vnode.children]);
}
@@ -191,7 +191,7 @@ const FRAME_BUDGET = 100;
////////////////////////////////////////////////////////////////////////////////
{
const Fader: m.Comp<{}, {}> = {
const Fader: m.Comp = {
onbeforeremove(vnode) {
vnode.dom.classList.add("fade-out");
return new Promise(resolve => {
@@ -227,7 +227,7 @@ const FRAME_BUDGET = 100;
}
};
const Form: m.Comp<{term: string}, {}> = {
const Form: m.Comp<{term: string}> = {
oninit(vnode) {
state.term = vnode.attrs.term || ""; // populated from the `history.state` property if the user presses the back button
},
@@ -239,7 +239,7 @@ const FRAME_BUDGET = 100;
}
};
const Layout: m.Comp<{}, {}> = {
const Layout: m.Comp = {
view(vnode) {
return m(".layout", vnode.children);
}
+36 -2
View File
@@ -1,5 +1,5 @@
import m = require('mithril');
import { Component, FactoryComponent, Vnode } from 'mithril';
import * as m from 'mithril';
import { Component, ClosureComponent, FactoryComponent } from 'mithril';
///////////////////////////////////////////////////////////
// 0.
@@ -50,6 +50,13 @@ const comp2: FactoryComponent<Comp2Attrs> = vnode => ({ // vnode is inferred
}
});
// 2a. Test ClosureComponent type alias
const comp2a: ClosureComponent<Comp2Attrs> = vnode => ({ // vnode is inferred
view({attrs: {title, description}}) { // Comp2Attrs type is inferred
return [m('h2', title), m('p', description)];
}
});
///////////////////////////////////////////////////////////
// 3.
// Declares attrs type inline.
@@ -80,6 +87,31 @@ const comp3: FactoryComponent<{pageHead: string}> = () => ({
}
});
// 3.a Test ClosureComponent type alias
const comp3a: ClosureComponent<{pageHead: string}> = () => ({
oncreate({dom}) {
// Can do stuff with dom
},
view({attrs}) {
return m('.page',
m('h1', attrs.pageHead),
m(comp2,
{
// attrs is type checked - nice!
title: "A Title",
description: "Some descriptive text.",
onremove(vnode) {
console.log("comp2 was removed");
},
}
),
// Test other hyperscript parameter variations
m(comp1, m(comp1)),
m('br')
);
}
});
///////////////////////////////////////////////////////////
// 4.
// Stateful component using closure method & var
@@ -152,7 +184,9 @@ m.route(document.body, '/', {
'/comp0': comp0,
'/comp1': comp1,
'/comp2': comp2,
'/comp2a': comp2a,
'/comp3': comp3,
'/comp3a': comp3a,
'/comp4': comp4,
'/comp5': comp5
});
+1 -1
View File
@@ -89,7 +89,7 @@ route(document.body, '/', {
test4: {
onmatch(args, path) {
// Must provide a Promise type if we want type checking
return new Promise<Component<{title: string}, {}>>((resolve, reject) => {
return new Promise<Component<{title: string}>>((resolve, reject) => {
resolve(component2);
});
}