Miguel Lattuada Miguel Lattuada - 29 days ago 6
Javascript Question

Compiled typescript. Function prototype lost reference to "this"

I working on a todo-app example with Redux and Maquettejs using Typescript. I just compile typescript, and then I use browserify to bundle all the .js files (this files contains application .ts files, and the libraries [redux, maquettejs]), I get no errors when compiling and everything is ok.

The problem comes when I try to see the result on the browser I get this error.

enter image description here

At least for me it makes no sense since it's explicit defined. I'm not an expert to judge the compiled code but in case I created a mocked implementation http://jsbin.com/tenohitumi/edit?js,console,output and it works as expected. I do not really get what's happening.

Just in case this is the class "App" written with typescript.



import { h, VNodeProperties, VNode } from 'maquette';
import { Store } from 'redux';
import { TodoList } from './Todolist';

export class App {

constructor(private store: Store<any>) {
}

render(): VNode {
this.store;
return h('div.main-component', [
new TodoList(this.store).render()
]);
}
}

// This is how I create the instance (it's in a different file)

import { createStore } from 'redux';
import { createProjector } from 'maquette';

import * as I from './interfaces/app';
import { MainReducer } from './reducers';
import { App } from './components/App';

let store = createStore(MainReducer);

let projector = createProjector();


document.addEventListener('DOMContentLoaded', function () {
let app = new App(store);
projector.append(document.body, app.render);
});





I would like to know if, is there anyway that something outside the anonymous function (in the bundle itself) could affect the value of "this", or prevent this to be set?

Answer

As @squint answered in a comment, the render method is getting orphaned from its App instance when you pass it to projector.append. Consider replacing the original line

projector.append(document.body, app.render);

with

projector.append(document.body, () => app.render());

Alternatively, you can define render using an arrow function instead, which won't holds on to its original reference to this.

export class App {
    constructor(private store: Store<any>) {
    }

    render = (): VNode => {
        return h('div.main-component', [
            new TodoList(this.store).render()
        ]);
    }
}
Comments