Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to how we use widgets programmatically in a render #267

Closed
matt-gadd opened this issue Feb 21, 2019 · 1 comment
Closed

Changes to how we use widgets programmatically in a render #267

matt-gadd opened this issue Feb 21, 2019 · 1 comment
Labels
enhancement New feature or request next Issue/Pull Request for the next major version

Comments

@matt-gadd
Copy link
Contributor

matt-gadd commented Feb 21, 2019

Enhancement
As part of dojo 6.0.0 we are looking at improving our types when using TSX or the v() and w() pragma's.

At the moment, to use a widget in a render function programmatically you use the w() pragma like so:

render() {
  return w(Something, { a: 'yo' });
}

Under the hood we pull the properties and children types off of the class. This works well in most scenario's apart from render props:

render() {
  return w(Foo, { 
    renderer: (thing) {
      // thing cannot be inferred
    }
  });
}

Unfortunately when using a render prop like so, the argument thing in this case cannot be inferred as it would take multiple passes, first to infer the properties off the generic, then to infer the properties off the renderer function (see here: microsoft/TypeScript#26418, this may change in the future)

By separating one of these passes, we can gain inference back on render props. The nicest way I can think of doing this, which also has ergonomic benefits, is to wrap the widget class into a factory. We do this kind of type factory in other places like stores to similar effect. An example of the new ergonomics:

Widget authoring:

interface FooProperties {
  renderer(thing: string): DNode | DNode[];
}

class Foo extends WidgetBase<FooProperties> {
  render() {
    const { renderer } = this.properties;
    return renderer('hello');
  }
}
// this is the new important bit
export default widget(Foo);

Widget usage:

import Foo from './Foo';

export class App extends WidgetBase {
  render() {
    return v('div', [
      Foo({
        renderer(thing) {
         // thing is inferred as string
        }
      })
    ]);
  }
}

As you can see, it would then no longer be necessary to use the w() pragma at all, users would just import the factory and use it. As a nice side effect it also means this formats a lot nicer than w() with prettier too (a common complaint).

The "magic" widget() factory just factories a WNode under the hood. We can also make this backwards compatible, so if you use a new factoried widget the old way with w() call it would still work.

@matt-gadd matt-gadd added enhancement New feature or request next Issue/Pull Request for the next major version labels Feb 21, 2019
@matt-gadd matt-gadd mentioned this issue Feb 21, 2019
3 tasks
@matt-gadd
Copy link
Contributor Author

This will require a change in the registry transformer at https://github.com/dojo/webpack-contrib, at the moment it looks for w() calls for code splitting which will no longer suffice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request next Issue/Pull Request for the next major version
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant