Credo che l'utilizzo di una combinazione di interfacce e classi base possa funzionare per te. Applicherà i requisiti comportamentali al momento della compilazione (rq_ post "sotto" si riferisce a un post sopra, che non è questo).
L'interfaccia imposta l'API comportamentale che non viene soddisfatta dalla classe base. Non sarai in grado di impostare i metodi della classe base per fare appello ai metodi definiti nell'interfaccia (perché non sarai in grado di implementare quell'interfaccia nella classe base senza dover definire tali comportamenti). Forse qualcuno può inventare una cassaforte trucco per consentire la chiamata dei metodi di interfaccia nel genitore.
Devi ricordare di estendere e implementare nella classe che istanzerai. Soddisfa le preoccupazioni sulla definizione del codice runtime-fail. Inoltre, non sarai nemmeno in grado di chiamare i metodi che potrebbero vomitare se non avessi implementato l'interfaccia (come se provassi a creare un'istanza della classe Animal). Ho provato a far sì che l'interfaccia estendesse BaseAnimal in basso, ma nascondeva il costruttore e il campo "name" di BaseAnimal da Snake. Se fossi stato in grado di farlo, l'uso di un modulo e delle esportazioni avrebbero potuto impedire l'istanza diretta accidentale della classe BaseAnimal.
Incollalo qui per vedere se funziona per te: 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);
Ho trovato la risposta di FristvanCampen come linkato di seguito. Dice che le classi astratte sono un anti-modello, e suggerisce che una istanza di base "classi astratte" usando un'istanza iniettata di una classe di implementazione. Questo è giusto, ma ci sono argomenti contrari. Leggi per te:
https://typescript.codeplex.com/discussions/449920
Parte 2: ho avuto un altro caso in cui volevo una classe astratta, ma mi è stato impedito di utilizzare la mia soluzione sopra, perché i metodi definiti nella "classe astratta" dovevano fare riferimento ai metodi definiti nell'interfaccia corrispondente. Quindi, attrezzo il consiglio di FristvanCampen, in un certo senso. Ho la classe "astratta" incompleta, con implementazioni di metodi. Ho l'interfaccia con i metodi non implementati; questa interfaccia estende la classe "astratta". Ho quindi una classe che estende il primo e implementa il secondo (deve estendersi entrambi perché altrimenti il super costruttore non è accessibile). Vedi l'esempio (non eseguibile) di seguito:
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;
}
}
e
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;
}