打字稿错误的上下文

时间:2012-10-07 08:04:33

标签: knockout.js typescript

代码:

export class ViewModel {
        public users: knockout.koObservableArrayBase;

        constructor () {
            this.users = ko.observableArray([]);
            this.removeUser = this.removeUser.bind(this);//<-- Here compiller shows error
        }

        removeUser(user: User): void {
            this.users.remove(user);
        }
}

HTML:

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Surname</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: users">
        <tr>
            <td><a href="#" data-bind="click: $root.removeUser">Remove</a></td>
            <td data-bind="text: name"></td>
            <td data-bind="text: surname"></td>
        </tr>
    </tbody>
</table>

问题在于removeUser方法。默认情况下,如果我没有绑定上下文,这= = UserToDelete - 而不是viewModel对象。如果我添加到构造函数:this.removeUser = this.removeUser.bind(this); (manually enforce context),那么上下文就是这个== viewmodel,但是然后TypeScript抱怨“无法将函数转换为(user:User)=&gt; void需要一个调用签名,但是函数缺少一个“。

5 个答案:

答案 0 :(得分:6)

我不熟悉ko所以也许有更好的方法来解决上下文切换,但是你的打字稿编译错误是由'bind'返回类型'Function'引起的,它与'removeUser'的类型不兼容。您应该能够通过将返回的函数转换为原始类型签名来解决此问题,如下所示:

this.removeUser = <(user: User) => void> this.removeUser.bind(this);

答案 1 :(得分:2)

我有同样的问题,这就是为什么我想出了以下基类来解决我的问题

export class ViewModelBase {
    private prefix: string = 'On';

    public Initialize() {
        for (var methodName in this) {
            var fn = this[methodName];
            var newMethodName = methodName.substr(this.prefix.length);
            if (typeof fn === 'function' && methodName.indexOf(this.prefix) == 0 && this[newMethodName] == undefined) {
                this[newMethodName] = $.proxy(fn, this);
            }
        }
    }
}

这样做会循环所有类的成员,如果一个方法以On开头,它将创建一个没有On的新方法,它将使用正确的上下文调用原始方法。

不是$.proxy是一个jquery调用,所以需要jquery才能工作。

答案 2 :(得分:2)

另一种方法是更改​​点击绑定,以使用JavaScript的 bind 功能强制this的值作为您的视图模型:{{1 }}

请注意,data-bind="click: $root.MyFunc.bind($root)"和点击$data对象仍会作为<{1}}的参数从Knockout传入,如 click binding 所述规格。如果您需要覆盖传递给event的参数,只需将它们传递到MyFunc之后的绑定函数中,如下所示:MyFunc。从技术上讲,这些参数将预先到Knockout提供的参数,并提供参数$root

答案 3 :(得分:1)

嗯,最简单的解决方案以及我通常用typescript和knockout js做的事情是我没有在原型上声明从knockout调用的函数,而是在构造函数中。所以,我会这样做:

export class ViewModel {
        public users: knockout.koObservableArrayBase;
        removeUser:(user: User) => void;

        constructor () {
            this.users = ko.observableArray([]);
            this.removeUser = (user:User) => {
                this.users.remove(user);
            }
        }
}

答案 4 :(得分:1)

我遇到了同样的问题。要获得正确的上下文,您可以使用clickbinding传递的参数。 clickbinding传递2个参数,即用户和点击的jquery事件。

如果您使用jquery事件,而不是使用ko.contextFor()函数,则可以获得正确的上下文。

您的功能类似于:

removeUser(user: User, clickEvent: any): void {
    var self = ko.contextFor(clickEvent.srcElement).$root;
    self.users.remove(user);
}