JavaScript的奇妙方面之一是对象可以从其他对象继承封装的多种不同方式。但是,从这个角度来看,TypeScript对编写模块的可能性施加了严格的限制。
在JavaScript中,您可以选择通过使用 Constructor Hijacking (该语言的一种极为强大的功能)来实现多重继承-而是Mixin功能。
var Base = function Base() {
function f() {
console.log('datum: %s', this.datum);
}
function method() {
this.a();
this.b();
this.c();
}
// export precepts
this.datum = true;
this.f = f;
this.method = method;
return this;
};
var A = function A() {
function a() {
this.f();
}
// export precepts
this.a = a;
return this;
};
var B = function B() {
function b() {
this.f();
}
// export precepts
this.b = b;
return this;
};
var C = function C() {
function c() {
this.f();
}
// export precepts
this.c = c;
return this;
};
var Klass = function Klass() {
var config = { };
function init() {
this.method();
}
// export precepts
Base.call(this);
A.call(this);
B.call(this);
C.call(this);
this.config = config;
this.init = init;
return this;
};
var klass = new Klass();
klass.init();
// > datum: true
// > datum: true
// > datum: true
这使开发人员可以将代码分解为离散的模块,这些模块仅需遵循某种模式或约定即可扩展另一个模块,从而保持SOLID原始的“单一责任原则”和“开闭原则”。
上面的代码应记录字符串datum: true
3次。这是因为Klass
修饰(或混入)Base
类,以便类A-C
在调用{{时不会抛出运行时错误。 1}}。该过程的CallStack如下所示:
CallStack是相当随意和琐碎的。另外,该代码可以看作是非SOLID代码,但是只要假设我们正在使用模板方法模式,就可以避免示例的繁琐。
此外,毫无疑问,将有一个灵魂要鼓起勇气,谈论我们对上述示例的所有了解如何违反TypeScript。请记住,“ TypeScript是JavaScript的超集”是简单,明显和公然的错误-我什至不会争论为什么,如果您正在使用TypeScript,您应该已经知道这一点。
鉴于上面的代码,如何使用有效的TypeScript语法实现这种功能?我仍然愿意在必要时利用“设计模式”,尽管这仍然不理想。
答案 0 :(得分:0)
Mixins为您提供所需的大部分东西。您的示例为:
class Base {
datum = true;
// We can't make these methods abstract because TypeScript currently
// doesn't support tracking whether mixins implement abstract methods.
a() {
throw new Error("not implemented");
}
b() {
throw new Error("not implemented");
}
c() {
throw new Error("not implemented");
}
f() {
console.log('datum: %s', this.datum);
}
method() {
this.a();
this.b();
this.c();
}
}
function mixA<Orig extends {new(...args: any[]): Base}>(base: Orig) {
return class extends base {
a() {
this.f();
}
};
}
function mixB<Orig extends {new(...args: any[]): Base}>(base: Orig) {
return class extends base {
b() {
this.f();
}
};
}
function mixC<Orig extends {new(...args: any[]): Base}>(base: Orig) {
return class extends base {
c() {
this.f();
}
};
}
class Klass extends mixA(mixB(mixC(Base))) {
config = {};
init() {
this.method();
}
}
var klass = new Klass();
klass.init();