Acredito que o uso de uma combinação de interfaces e classes base possa funcionar para você. Ele aplicará requisitos comportamentais em tempo de compilação (rq_ post "below" refere-se a um post acima, que não é este).
A interface define a API comportamental que não é atendida pela classe base. Você não poderá definir métodos da classe base para chamar os métodos definidos na interface (porque não poderá implementar essa interface na classe base sem precisar definir esses comportamentos). Talvez alguém possa inventar um truque seguro para permitir a chamada dos métodos de interface no pai.
Você deve se lembrar de estender e implementar na classe que você instanciará. Satisfaz as preocupações sobre a definição do código de falha de tempo de execução. Você também não poderá chamar os métodos que vomitariam se não implementasse a interface (como se você tentasse instanciar a classe Animal). Tentei fazer com que a interface estendesse o BaseAnimal abaixo, mas ocultou o construtor e o campo 'name' do BaseAnimal do Snake. Se eu pudesse fazer isso, o uso de um módulo e as exportações poderiam ter impedido a instanciação direta acidental da classe BaseAnimal.
Cole isso aqui para ver se funciona para você: 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);
Me deparei com a resposta de FristvanCampen como link abaixo. Ele diz que as classes abstratas são um antipadrão e sugere que uma instância instale classes 'abstratas' usando uma instância injetada de uma classe de implementação. Isso é justo, mas existem contra-argumentos. Leia você mesmo:
https://typescript.codeplex.com/discussions/449920
Parte 2: tive outro caso em que desejava uma classe abstrata, mas fui impedido de usar minha solução acima, porque os métodos definidos na "classe abstrata" precisavam se referir aos métodos definidos na interface correspondente. Então, eu uso o conselho de FristvanCampen, mais ou menos. Eu tenho a classe "abstrata" incompleta, com implementações de métodos. Eu tenho a interface com os métodos não implementados; essa interface estende a classe "abstrata". Em seguida, tenho uma classe que estende o primeiro e implementa o segundo (deve estender ambos porque o super construtor é inacessível de outra forma). Veja o exemplo (não executável) abaixo:
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;
}