Is there a way to enhance Backbone.Events within a Typescript ES6 Class?

Trying to incorporate Backbone's Events properties into a TypeScript class has hit a roadblock. Here's what I'm encountering...

class Foo {
    constructor () {
        _.assign(this, Backbone.Events); // or _.extend()
        this.stopListening(this.otherInstance);
    }
}

let bar = new Foo();
bar.on("myevent", handler);

The problem arises when these compile time errors show up:

  • Error TS2339: Property 'stopListening' does not exist on type 'Foo'.
  • Error TS2339: Property 'on' does not exist on type 'Foo'.

I'm not well-versed in how TypeScript deals with this issue, but it seems like something that should be manageable.

Note: searching for a solution that can easily be implemented across multiple classes requiring Backbone.Events functionality (i.e. avoiding the repetition of copying/pasting all the on, off, listenTo... methods, or using some complex proxy approach).

Given that Backbone.Events is simply an object, traditional ES6 syntax won't allow me to extend it. For example:

class Foo extends Backbone.Events {}

Any suggestions?

Answer №1

if you switch from using _.assign to _.extend, the code will function properly,

Check out this Plunker

    class Foo {
      constructor () {
         _.extend(this, Backbone.Events);
      }
    }

    let bar : any = new Foo();

    bar.on("alert", function(msg) {
      alert("Triggered " + msg);
    });

    bar.trigger("alert", "an event");

revised the code to avoid compile time errors.

UPDATE

you can create a class that includes all functions defined for Backbone.Events, and its constructor can extend Backbone.Events, overriding all the methods for intellisense and type checking purposes.

updated version on plunker

 class CustomEvents {
    constructor() {
      _.extend(this, Backbone.Events);
    }

    on(eventName: string, callback?: Function, context?: any): any { return; };
    off(eventName?: string, callback?: Function, context?: any): any { return; };
    trigger(eventName: string, ...args: any[]): any { return; };
    bind(eventName: string, callback: Function, context?: any): any { return; };
    unbind(eventName?: string, callback?: Function, context?: any): any { return; };

    once(events: string, callback: Function, context?: any): any { return; };
    listenTo(object: any, events: string, callback: Function): any { return; };
    listenToOnce(object: any, events: string, callback: Function): any { return; };
    stopListening(object?: any, events?: string, callback?: Function): any { return; };
  }

you can extend any class with the CustomEvents class as shown below,

  class Foo extends CustomEvents {
    constructor(){
      super(); 
    }
  }

https://i.sstatic.net/a9WSt.png

Answer №2

When working with Backbone.Events, it's important to note that event handling is attached directly to the object itself rather than its .prototype. Here is a solution for proper implementation:

import {Events} from 'backbone';

interface IEventEmitter extends Events {
    emit(event: string, ...args: any[]);
}

function _EventEmitter() {}
_EventEmitter.prototype = Events;
_EventEmitter.prototype.emit = (Events as any).trigger;
export const EventEmitter: new() => IEventEmitter
    = _EventEmitter as any as new() => IEventEmitter;

You can now use inheritance like this:

class Cat extends EventEmitter {

}

var cat = new Cat;
cat.on('meow', () => console.log('Cat just meowed'));
cat.emit('meow');

Answer №3

  1. Download typings from this source - https://www.npmjs.com/package/@types/backbone
  2. Add the Backbone.EventsMixin implementation right after including the Backbone script:

Backbone.EventsMixin = function () {
    _.assign(this, Backbone.Events);
}

  1. You can now utilize it as follows:

class SomeClass extends Backbone.EventsMixin

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Modifying various states within React using the useState() hook

Curiosity strikes me - what actually happens when I modify more than one state in a handler function? Will they be updated simultaneously, or will the changes occur sequentially? const [x, setX] = useState(0) const [y, setY] = useState(0) const handlerFu ...

Retrieve data from a ng-repeat variable within a controller

Below is the current code snippet: HTML <center><li ng-repeat = "x in items | orderBy: 'priority'"> <!-- color code priorities --> <span ng-style="cmplt" ng-class="{ red: x.type == &apo ...

How to use jQuery to hide list items after a certain threshold

$('li[data-number=4]').after().hide(); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <ul> <li data-number="0"">1</li> <li data-number="1">2</li> ...

Is the variable not being initialized outside of the function?

I'm really struggling with this async issue. I can't seem to get it to work because the summonerData array is not being set. I have a feeling it has something to do with async, but I'm not sure how to troubleshoot it. var summonerName = req ...

Check the type of the indexed value

I need help with a standard interface: interface IProps<T> { item: T; key: keyof T; } Is there a way to guarantee that item[key] is either a string or number so it can be used as an index for Record<string | number, string>? My codeba ...

Incorporate ajax into the JavaScript geocoder functionality

After retrieving the latitude and longitude coordinates from the maps, I am trying to send the address to another PHP file using Ajax in JavaScript. Unfortunately, the Ajax is not working properly for me. I am puzzled as both the Ajax code and the JavaScr ...

Struggling to convert my VueJS component from JavaScript to TypeScript, feeling a bit lost

I am new to VueJS and I am facing a challenge converting my VueJS project to use TypeScript. I have been trying to bind functions to certain variables in JavaScript, but I am struggling with accomplishing the same in TypeScript. Even though there are no er ...

Creating a layout of <video> components in vue.js, complete with the ability to rearrange and resize them through drag and drop functionality

Despite trying numerous libraries and Vue.js plugins, I have yet to find one that meets all of my requirements. I am in need of creating a grid of video HTML elements that are draggable and resizable with a consistent aspect ratio of 16:9. Additionally, I ...

Is it feasible to add on to an existing object in the database? (Using Node.js and Mongoose

After saving an object to the database using the following code: var newObject = new PObject({ value : 'before', id : 123456 }); newObject.save(function(err) { if (err) ...

Reorganizing an array while initializing it in Javascript

Upon further review of responses, I have decided to exclude single characters, code, and special characters from the initial creation of the words array. Utilizing the script found at THIS PAGE and executing it in the console on any website, we obtain an ...

Combine an array of objects into a regular object

Imagine having an array structure as shown below: const student = [ { firstName: 'Partho', Lastname: 'Das' }, { firstName: 'Bapon', Lastname: 'Sarkar' } ]; const profile = [ { education: 'SWE', profe ...

Element search feature added to dropdown menu

I am seeking valuable advice and guidance to navigate through this challenging situation. Here's the scenario: I need to create a dropdown menu similar to the one below. <ul class="dropdown"> <li><a href="#">America</a></l ...

What is the best way to update information in the `App` component using Vue?

Within Vue, I have an App component that utilizes the <router-view> to extend the functionality of a Login component. My goal is to update specific data within the App component when a button is clicked in the Login component. Is this type of inter ...

What is the method for executing a function enclosed within a variable?

As someone new to the world of Java, I have encountered a puzzling issue with some code related to a game. Specifically, there seems to be an obstacle when it comes to utilizing the navigator function. When I click on this function in the game, some sort o ...

Remove the default shake effect in react-native (expo)

I am currently working on a project using React Native for iOS, with the react-native-shake-event library and I am using Expo. However, when I try to shake the device, the dev-menu pops up because it detects the "shake event", preventing me from testing my ...

Modifying the Redux state using an array with prototypes

In my React application, I am utilizing Redux along with the ChartJS library to create charts. Occasionally, when I extract an array from the global Redux state, it appears in this format: ejeY: Array(7) 0: 43783 1: 85001 2: 100960 3: 752 ...

Connecting nodes to edges based on their unique ids in the d3.js graph library

I am encountering an issue with this code while trying to integrate it with a new JSON object called 'new_json'. Specifically, I need the links in this code to be created based on the nodes' IDs. Can anyone provide assistance with this? va ...

Activate function on Selected DIV

Within this div, I have set the tabindex attribute to '-1' so that it can be focused on mouse click. <div tabindex='-1'></div> .div:focus{//some style} My goal is to use jQuery to perform an action when a user clicks on th ...

Generate random div elements and insert them dynamically into a fixed-sized container using AngularJS. The number of div elements created can range anywhere from 0 to

Within a div of fixed size, dynamically generated div elements are displayed using ng-repeat. The inner divs should adjust their size to accommodate the number of child divs present - for example, if only one div is present, it should take up 100% of the s ...