support for class-factory mixins
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()
Thank you a lot ^_^. We will add it soon.
I'm curious if it can be better than TS's. There are several problems with mixins in TypeScript:
-
returning abstract classes doesn't work, but maybe it doesn't apply if Hegel will not have
abstract - https://github.com/microsoft/TypeScript/issues/32080 (a bunch of problems described in there, shows how difficult it is to make mixins in TypeScript)
-
Implicit return types not supported by declaration files, makes mixins not an option when declaration emit is enabled (means we can't use mixins with the new
tsx --buildCLI). (related issue: https://github.com/microsoft/TypeScript/issues/35822, listing all issues of features not supported in declaration files)
Another example
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?
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.
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.