Search code examples
javascriptbackbone.jstypescript

Backbone, TypeScript, and super


I am working through the book "Mastering TypeScript" in which the author demonstrates the use of Backbone to generate the models, collections and views.

I have the following class defined:

export class ContactItemView extends Backbone.View<cm.ContactModel> {
    template: (properties?: any) => string;
    constructor(options?: any) {
        this.className = "contact-item-view";
        this.template = _.template(contactItemSnippet);
        this.events = <any>{ 'click': this.onClicked };
        super(options);
    }
...
}

Unfortunately, TypeScript will not compile this with the error:

Build: 'super' must be called before accessing 'this' in the constructor of a derived class

Yet, if I move the call to super above "this"

export class ContactItemView extends Backbone.View<cm.ContactModel> {
    template: (properties?: any) => string;
    constructor(options?: any) {

        super(options);

        this.className = "contact-item-view";
        this.template = _.template(contactItemSnippet);
        this.events = <any>{ 'click': this.onClicked };
     }
...
}

then my event does not fire. The only thing I have been able to do to resolve this is moving the call to super, in the resulting JavaScript code to after the use of "this", thus modifying what TypeScript has compiled.

Is there a way to get my events to work while still adhering to the proper TypeScript rules?


Solution

  • Using "normal" Backbone doesn't work too well, but I was able to get it done with a bit more DIY approach based on the article linked by Ryan:

    export class ContactItemView extends Backbone.View<cm.ContactModel> {
        static template: (properties?: any) => string = _.template(contactItemSnippet);
        constructor(options?: any) {
            super(options);
            this.events = <any>{ 'click': this.onClicked };
        }
    
        events(): Backbone.EventsHash {
            return {
              // events
            };
        }
    
        render(): ContactItemView {
            this.$el
              .addClass("contact-item-view")
              .html(ContactItemView.template(...));
            return this;
        }
        ...
    }