Skip to content

Commit

Permalink
Model in modelView does not have to return ReactivesObject
Browse files Browse the repository at this point in the history
  • Loading branch information
paldepind committed Aug 18, 2019
1 parent 9cd611f commit 3c66646
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 7 deletions.
24 changes: 17 additions & 7 deletions src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,20 @@ export function isComponent(c: any): c is Component<any, any> {
return c instanceof Component;
}

type Reactive = Behavior<any> | Stream<any> | Future<any>;

export interface ReactivesObject {
[a: string]: Behavior<any> | Stream<any> | Future<any>;
[a: string]: Reactive;
}

/**
* Removes all properties from a type except those that are either
* streams, behaviors, or futures.
*/
type OnlyReactives<R> = {
[K in keyof R]: R[K] extends Reactive ? R[K] : never;
};

const placeholderProxyHandler = {
get: function(target: any, name: string): Behavior<any> | Stream<any> {
if (!(name in target)) {
Expand Down Expand Up @@ -336,7 +346,7 @@ function addErrorHandler(modelName: string, viewName: string, obj: any): any {
});
}

class ModelViewComponent<M extends ReactivesObject, V> extends Component<
class ModelViewComponent<M extends Record<string, any>, V> extends Component<
M,
{}
> {
Expand Down Expand Up @@ -381,20 +391,20 @@ class ModelViewComponent<M extends ReactivesObject, V> extends Component<
export type ModelReturn<M> = Now<M> | Iterator<any>;
export type Model<V, M> = (v: V) => ModelReturn<M>;
export type Model1<V, M, A> = (v: V, a: A) => ModelReturn<M>;
export type View<M, V> = (m: M) => Child<V>;
export type View1<M, V, A> = (m: M, a: A) => Child<V>;
export type View<M, V> = (m: OnlyReactives<M>) => Child<V>;
export type View1<M, V, A> = (m: OnlyReactives<M>, a: A) => Child<V>;

export function modelView<M extends ReactivesObject, V>(
export function modelView<M extends Record<string, any>, V>(
model: Model<V, M>,
view: View<M, V>,
toViewReactiveNames?: string[]
): () => Component<M, {}>;
export function modelView<M extends ReactivesObject, V, A>(
export function modelView<M extends Record<string, any>, V, A>(
model: Model1<V, M, A>,
view: View1<M, V, A>,
toViewReactiveNames?: string[]
): (a: A) => Component<M, {}>;
export function modelView<M extends ReactivesObject, V>(
export function modelView<M extends Record<string, any>, V>(
model: any,
view: any,
toViewReactiveNames?: string[]
Expand Down
9 changes: 9 additions & 0 deletions test/component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,15 @@ describe("modelView", () => {
expect(dom.querySelector("span")).to.not.exist;
expect(toplevel).to.equal(true);
});
it("model can return non-reactive but the view can't use it", () => {
const c = modelView(
({}) => H.Now.of({ foo: H.Behavior.of("foo"), bar: "bar" }),
// Using `bar` in the view below would give a type error.
({ foo }) => span(["World", dynamic(foo)])
)();
const { available } = testComponent(c);
assert.strictEqual(available.bar, "bar");
});
});

describe("view", () => {
Expand Down

0 comments on commit 3c66646

Please sign in to comment.