hegel icon indicating copy to clipboard operation
hegel copied to clipboard

support for class-factory mixins

Open trusktr opened this issue 5 years ago • 5 comments

The following plain JS doesn't work:

function Foo(Base) {
  return class Foo extends Base {
    foo() { console.log('foo') }
  }
}

class Bar {
  bar() { console.log('bar') }
}

class Baz extends Foo(Bar) {
  baz() { console.log('baz') }
}

const b = new Baz
b.foo()
b.bar()
b.baz()

try link

trusktr avatar May 20 '20 17:05 trusktr

Thank you a lot ^_^. We will add it soon.

JSMonk avatar May 20 '20 17:05 JSMonk

I'm curious if it can be better than TS's. There are several problems with mixins in TypeScript:

Another example

trusktr avatar May 20 '20 19:05 trusktr

The following is amazing, yet horrific: https://www.bryntum.com/blog/the-mixin-pattern-in-typescript-all-you-need-to-know-part-2/

It is amazing that that technique for making class-factory mixins in TypeScript can make them more class-like, but the syntax, non-DRY-ness (or WET-ness as in Write Everything Twice), and complicated mapped types are the horrific part.

If Hegel could achieve mixins but without all that complexity, and with support for declaration emit (or in other words full support for mixins as library exports, unlike in TypeScript), I would seriously consider dropping TypeScript for Hegel. Is it possible, without mapped types? I suppose it would be like hidden mapped types within the Hegel implementation, without mapped types required by the user?

trusktr avatar Jun 06 '20 06:06 trusktr

As another example of the current complexity, here's my Mixin implementation (which itself isn't that long) and the unit tests (but the README has better more practical examples). But it gets complicated at the usage sites, for example.

It is riddled with issues. For example, in that last example, if I change the lines

const _Base = Constructor(Base)
const Parent = Observable.mixin(TreeNode.mixin(_Base))

to

const Parent = Observable.mixin(TreeNode.mixin(Constructor(Base)))

it completely breaks (for no intuitive reason). The Constructor(Base) constructor expression must be assigned to a new variable first, for it to work.

It's little things like that, plus all the other issues like having to follow the patterns with the mapped typed that you see in that example, that make it all too complicated compared to plain JS.

trusktr avatar Jun 06 '20 06:06 trusktr

I'm also interested in class mixins, and the developer experience with TypeScript has been quite painful in this regard.

Here is one more issue which wasn't mentioned above: microsoft/TypeScript#17744. See my comment there for an overview of techniques that I tried, including the workaround for using protected methods.

Generally, this might be beneficial for web components libraries, such as Lion, Vaadin, Spectrum and others. We have to use class mixins when creating custom elements classes that extend HTMLElement.

web-padawan avatar Jul 15 '20 08:07 web-padawan