There is in fact a way to do something like what you are trying to do, albeit maybe not with Typescript interfaces, as Günter Zöchbauer is correct that they do not exist as such once the code is transpiled to javascript.
You can use a parent class however. The parent can probably be an abstract class. Now that I think about it, interfaces should work too IF they are transpiled into the runtime namespace, which I do not know if they are.
@Component({
selector: 'square',
providers: [provide(Shape, useExisting: forwardRef( ()=>Square )]
})
class Square extends Shape {}
Refer to this discussion.
https://github.com/angular/angular/issues/8580
Now I want to leave my own example below for those using es5 like me, and for the sake of a more thorough use-case demonstration. I tried to balance the amount of extra detail such that the example makes sense as a whole without getting extraneous.
I needed to do some custom resize logic in a dashboard component, and I wanted several different types of chart directive to rerender themselves only after I performed my custom resize logic in the parent dashboard component. Some of my charts were components actually and it caused no problems. Anything else you need to make the following pattern work in es5 is standard. You do not need to include app.Renderable in the list of providers given to your NgModule.
renderable.class.js
(function(app) {
app.Renderable = ng.core.Class({
constructor : [function Renderable() {}],
render : function() {}
});
})(window.app || (window.app = {}));
chart-one.directive.js
(function(app) {
app.ChartOneDirective = ng.core.Directive({
selector : 'canvas[chart-one]',
inputs : ['config:chart-one'],
providers : [{
provide: app.Renderable,
useExisting: ng.core.forwardRef(function(){
return app.ChartOneDirective;
}),
}]
}).Class({
extends : app.Renderable,
constructor : [/* injections */ function ChartOneDirective(/* injections */) {
// do stuff
}],
// other methods
render : function() {
// render the chart
}
});
})(window.app || (window.app = {}));
chart-two.directive.js
(function(app) {
app.ChartTwoDirective = ng.core.Directive({
selector : 'canvas[chart-two]',
inputs : ['config:chart-two'],
providers : [{
provide: app.Renderable,
useExisting: ng.core.forwardRef(function(){
return app.ChartTwoDirective;
}),
}]
}).Class({
extends : app.Renderable,
constructor : [/* injections */ function ChartTwoDirective(/* injections */) {
// do stuff
}],
// other methods
render : function() {
// render the chart
}
});
})(window.app || (window.app = {}));
dashboard.component.js
(function(app) {
app.DashboardComponent = ng.core.Component({
selector : 'dashboard-component',
templateUrl : 'components/dashboard/dashboard.component.html',
host : {
'(window.resize)' : 'rerender()',
},
queries : {
renderables : new ng.core.ViewChildren(app.Renderable),
// other view children for resizing purposes
}
}).Class({
constructor : [/* injections */ function DashboardComponent(/* injections */) {
// do stuff
}],
resize : function() {
// do custom sizing of things within the dom
},
// other methods
rerender : function() {
this.resize();
this.renderables.forEach(function(r){
r.render();
});
}
});
})(window.app || (window.app = {}));
dashboard.component.html
<div #sizeMe>
<div class='canvas-wrapper'><canvas [chart-one]></canvas></div>
<div class='canvas-wrapper'><canvas [chart-two]></canvas></div>
<div class='canvas-wrapper'><canvas [chart-one]></canvas></div>
<div #sizeMeToo>
<div class='canvas-wrapper'><canvas [chart-two]></canvas></div>
<div class='canvas-wrapper'><canvas [chart-one]></canvas></div>
</div>
</div>
Now, in es5 javascript, it is actually unnecessary to extend the Renderable class in order for this to work. Furthermore, you can put more than one provider in your provider list, and thus allow your component or directive to be queried for my multiple tokens. Thus you could say you can "implement" several "interfaces" for the purposes of ViewChild selection in the classic javascript fashion of nothing being actually guaranteed.