Ich glaube, dass die Verwendung einer Kombination aus Schnittstellen und Basisklassen für Sie funktionieren könnte. Es werden Verhaltensanforderungen zur Kompilierungszeit durchgesetzt (rq_ post "unten" bezieht sich auf einen Beitrag oben, der nicht dieser ist).
Die Schnittstelle legt die Verhaltens-API fest, die von der Basisklasse nicht erfüllt wird. Sie können keine Basisklassenmethoden festlegen, um in der Schnittstelle definierte Methoden aufzurufen (da Sie diese Schnittstelle nicht in der Basisklasse implementieren können, ohne diese Verhaltensweisen definieren zu müssen). Vielleicht kann sich jemand einen sicheren Trick einfallen lassen, um das Aufrufen der Schnittstellenmethoden im übergeordneten Element zu ermöglichen.
Sie müssen daran denken, die zu instanziierende Klasse zu erweitern und zu implementieren. Es erfüllt Bedenken hinsichtlich der Definition von Laufzeitfehlercode. Sie können auch nicht einmal die Methoden aufrufen, die kotzen würden, wenn Sie die Schnittstelle nicht implementiert hätten (z. B. wenn Sie versuchen, die Animal-Klasse zu instanziieren). Ich habe versucht, die Schnittstelle das unten stehende BaseAnimal erweitern zu lassen, aber es hat den Konstruktor und das Feld 'name' von BaseAnimal vor Snake versteckt. Wenn ich dazu in der Lage gewesen wäre, hätte die Verwendung eines Moduls und von Exporten eine versehentliche direkte Instanziierung der BaseAnimal-Klasse verhindern können.
Fügen Sie dies hier ein, um zu sehen, ob es für Sie funktioniert: http://www.typescriptlang.org/Playground/
// The behavioral interface also needs to extend base for substitutability
interface AbstractAnimal extends BaseAnimal {
// encapsulates animal behaviors that must be implemented
makeSound(input : string): string;
}
class BaseAnimal {
constructor(public name) { }
move(meters) {
alert(this.name + " moved " + meters + "m.");
}
}
// If concrete class doesn't extend both, it cannot use super methods.
class Snake extends BaseAnimal implements AbstractAnimal {
constructor(name) { super(name); }
makeSound(input : string): string {
var utterance = "sssss"+input;
alert(utterance);
return utterance;
}
move() {
alert("Slithering...");
super.move(5);
}
}
var longMover = new Snake("windy man");
longMover.makeSound("...am I nothing?");
longMover.move();
var fulture = new BaseAnimal("bob fossil");
// compile error on makeSound() because it is not defined.
// fulture.makeSound("you know, like a...")
fulture.move(1);
Ich bin auf die Antwort von FristvanCampen gestoßen, wie unten verlinkt. Er sagt, dass abstrakte Klassen ein Anti-Muster sind, und schlägt vor, dass man 'abstrakte' Basisklassen unter Verwendung einer injizierten Instanz einer implementierenden Klasse instanziiert. Das ist fair, aber es werden Gegenargumente vorgebracht. Lesen Sie selbst:
https://typescript.codeplex.com/discussions/449920
Teil 2: Ich hatte einen anderen Fall, in dem ich eine abstrakte Klasse wollte, aber ich wurde daran gehindert, meine obige Lösung zu verwenden, da die definierten Methoden in der "abstrakten Klasse" auf die in der passenden Schnittstelle definierten Methoden verweisen mussten. Also, ich arbeite mit dem Rat von FristvanCampen. Ich habe die unvollständige "abstrakte" Klasse mit Methodenimplementierungen. Ich habe die Schnittstelle zu den nicht implementierten Methoden; Diese Schnittstelle erweitert die "abstrakte" Klasse. Ich habe dann eine Klasse, die die erste erweitert und die zweite implementiert (sie muss beide erweitern, da auf den Superkonstruktor sonst nicht zugegriffen werden kann). Siehe das (nicht ausführbare) Beispiel unten:
export class OntologyConceptFilter extends FilterWidget.FilterWidget<ConceptGraph.Node, ConceptGraph.Link> implements FilterWidget.IFilterWidget<ConceptGraph.Node, ConceptGraph.Link> {
subMenuTitle = "Ontologies Rendered"; // overload or overshadow?
constructor(
public conceptGraph: ConceptGraph.ConceptGraph,
graphView: PathToRoot.ConceptPathsToRoot,
implementation: FilterWidget.IFilterWidget<ConceptGraph.Node, ConceptGraph.Link>
){
super(graphView);
this.implementation = this;
}
}
und
export class FilterWidget<N extends GraphView.BaseNode, L extends GraphView.BaseLink<GraphView.BaseNode>> {
public implementation: IFilterWidget<N, L>
filterContainer: JQuery;
public subMenuTitle : string; // Given value in children
constructor(
public graphView: GraphView.GraphView<N, L>
){
}
doStuff(node: N){
this.implementation.generateStuff(thing);
}
}
export interface IFilterWidget<N extends GraphView.BaseNode, L extends GraphView.BaseLink<GraphView.BaseNode>> extends FilterWidget<N, L> {
generateStuff(node: N): string;
}