TypeScriptで多重継承が必要です。論理的には、多くの機能を階層に配置するのは良くありません。 1つの基本クラスといくつかの階層ブランチがあります。しかし、いくつかのメインロジックを別々のクラスに配置するためにミキシングを使用する必要があります。すべてのブランチで使用されるわけではないからです。
コード例の更新:
function Mixin = function(mixins:any[]){ // mixin decorator
return function(target){
mixins.forEach((mixin) => {
add every function from mixing to target prototype,
if functions with same name does not exists there,
so we are able to do calls to as example different render() functions
Will show it in OpenableItem
});
}
}
function element = function(){
return function(target){
target.prototype.element = function(){
return this.$el;
}
}
}
--------------------------------------------------------------------------------------
@element // every item will have this function as Root as Openable
class BaseItem{
y() => number; // we need to get y position of every item
}
OpenableMixin{
render() => render arrow only
open(){} => change arrow position and cause menu to fire change event
close(){} => change arrow position and cause menu to fire change event
}
class ItemsMixin extends OpenableMixing{// for now if item have childs it must be openable,
// but Responsive has only tasks and must be openable too
addItem(item: BaseItem) // need to add generics
removeItem(item: BaseItem)
}
--------------------------------------------------------------------------------------
@Mixin([ItemsMixin, ActivitiesMixin]) // it can have items and activities
class OpenableItem extends BaseItem implement ItemsMixin, ActivitiesMixin { // as in TypeScript docs
render(){
// call rendering from BaseItem class
super.render();
// call rendering from OpenableMixing
OpenableMixin.prototype.render.call(this);
// do some separate rendering for OpenableItem only
this.$el.append('line');
}
}
@Mixin([ItemsMixin]) // it can have items
class RootItem extends BaseItem implement ItemsMixin{ // and subitems functionality is only for Root class
subitems: Array<BaseItem> // need to add generics to be able to put here different item types
}
--------------------------------------------------------------------------------------
@element
class Menu{
items: Array<Item>
}
@element
class Timeline{
menu: Menu
listAllelement() => {
console.log(this.element());
console.log(this.menu.element());
this.menu.items.forEach((item) => {
console.log(item.element());
if(item.hasChilds()){ // really it must be (item instanceof RootItem || item instanceof OpenableItem)
item.items.forEach((subitem) => { // really we need some recursion here
console.log(subitem.element());
})
}
})
}
}
実際には、多重継承を実装する必要があるのはまれな状況であり、javascriptでこのような問題が発生することはほとんどありません。ただし、すべてのアイテムは、ニーズに応じて異なる機能を持つことができます。
いくつかのミックスインを持つことができるさまざまなアイテムがあることを想像してください。すべてをベースに入れるのは賢明ですか?そして、この問題に対するあなたのアプローチは何ですか?
@ kjetil-klaussenは正しい、TypeScript 2.2は ECMAscript 2017 mixinパターンのサポートを追加しました
完全なコードサンプルを次に示します。
// http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/
// https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#support-for-mix-in-classes
type Constructor<T> = new (...args: any[]) => T;
class S {
foo() {
console.log('foo from S');
}
}
// Here the possible SuperClass is set to {} (Object)
function Mixin1<T extends Constructor<{}>>(SuperClass: T) {
return class extends SuperClass {
foo() {
console.log('foo from Mixin1');
if (super.foo) super.foo();
}
};
}
// Here the possible SuperClass (S) is specified
function Mixin2<T extends Constructor<S>>(SuperClass: T) {
return class extends SuperClass {
foo() {
console.log('foo from Mixin2');
super.foo();
}
};
}
class C extends Mixin1(Mixin2(S)) {
foo() {
console.log('foo from C');
super.foo();
}
}
new C().foo();
この出力:
foo from C
foo from Mixin1
foo from Mixin2
foo from S
TypeScript 2.2が追加されました mix-insのサポート 。