Signalr 导出TypeScript模块会导致无法拾取接口

Signalr 导出TypeScript模块会导致无法拾取接口,signalr,typescript,Signalr,Typescript,我正在一起使用TypeScript和SignalR,并试图为生成的SignalR类定义静态类型。如果我做了这样的事情,它会起作用: ///<reference path="../Scripts/jquery-1.8.d.ts" /> ///<reference path="../Scripts/signalr-1.0.d.ts" /> interface SignalR { roomHub: Service.RoomHub; } module Service

我正在一起使用TypeScript和SignalR,并试图为生成的SignalR类定义静态类型。如果我做了这样的事情,它会起作用:

///<reference path="../Scripts/jquery-1.8.d.ts" />
///<reference path="../Scripts/signalr-1.0.d.ts" />

interface SignalR {
    roomHub: Service.RoomHub;
}

module Service {
        export var roomHub = $.connection.roomHub;
        export interface RoomHub { }
}
但是,当我这样做时,在
$.connection.roomHub
下会出现一条红色的曲线,编译器返回错误:“类型信号器上不存在属性'roomHub'


我当然不完全理解打字脚本,但我觉得这并不正确。我遇到编译器错误了吗?还是有其他的方法可以做到这一点

如果
信号器
对象具有实际成员,则需要使用
声明模块
语法<代码>接口声明仅描述类型上的成员(而不是描述现有对象)

///
///
声明模块信号器{
var-roomHub:Service.roomHub;
}
导出模块服务{
//现在好
导出变量roomHub=$.connection.roomHub;
导出接口RoomHub{}
}

我找到了一个解决办法。我将接口拉入一个单独的文件:

// File: ISignalR.ts
interface SignalR {
    roomHub: RoomHub;
}

interface RoomHub {
}
然后我在我的服务文件中引用了那个文件

///<reference path="../Scripts/jquery-1.8.d.ts" />
///<reference path="../Scripts/signalr-1.0.d.ts" />
///<reference path="ISignalR.ts" />

export module Service {
    export var roomHub = $.connection.roomHub;
}
///
///
///
导出模块服务{
导出变量roomHub=$.connection.roomHub;
}

奇怪的是,这是有效的。我不确定这是一个编译器错误,还是我一直误解的东西,但它显然与AMD模块支持相关的一些微妙的语义变化有关。我很想听到比我更熟悉TypeScript和/或要求JS模块的人的更多解释。

连接SignalR的方法不止一种,使用
createHubProxy
invoke
对TypeScript更友好:

export class FrameworkHub {

    private connection: HubConnection;
    private proxy: HubProxy;

    Init(): void {
        this.Connected = false;
        this.connection = $.hubConnection();
        this.connection.logging = true;
        // Binding with createHubProxy means you can use a string name, so no need to add dynamic properties to the hub
        this.proxy = this.connection.createHubProxy("MyHubName"); 
        this.wireEventListeners();
        this.initializeConnection();
    }

    // Binding with proxy.on means you can use a string name for the function, so no need to add dynamic properties to the hub.
    wireEventListeners(): void {
        this.proxy.on("HandleFrameworkMessage", (message: IFrameworkMessage) => {
            console.log("HandleFrameworkMessage: " + message.AccountID + " - " + message.ArmID);
            // Do something to handle the message here.
        });
    }

    initializeConnection(): void {
        //console.log("Framework Hub initializeConnection");
        var that = this;
        //Again, using invoke means passing a string argument.
        this.connection.start().done(() => {
            that.proxy.invoke("Connect", this.AccountID, this.ArmID).done((response:FrameworkHubResponse) => {
                //console.log("FHR: " + response.Success + " - " + response.Message);
                if (response.Success) {
                    // Do something.
                }
                else {
                    // Try again. Would be better with some kind of exponential back-off.
                    setTimeout(that.initializeConnection, 500);
                }
            });
        });
    }
}

这是一个从实际代码中略显粗糙的示例,但我发现它是使用SignalR的最佳TS方式。这类连接的文档如下:-请注意,因为文档并不总是与最近的更改保持同步。

使用准确的代码,我得到了相同的错误:
$.connection.roomHub
,以及消息“type signal上不存在属性'roomHub'。我想(我不确定)
接口
语法是合适的,因为它描述了
$.connection
对象呈现给世界的接口。如何声明$.connection?它在运行时在文件
jquery.signar-1.0.0-alpha2.js
中定义,在编译时,在定义文件
signalr-1.0.d.ts
()中,我仍然在思考signalr-那么,使用这种方法比使用自动生成的代理有什么好处呢?如果我在TS中使用自动生成的代理,是的,我需要手动定义它们的接口-但我想我有点喜欢关注点的分离,这样我就不会在我控制的代码中挂起任何神奇的字符串。当然,理想情况下,让SignalR在JS代码旁边生成TS接口会很棒。这是一个风格问题,真的。我仍然习惯于使用signar,但这种方式更像是使用任何其他PubSub组件(JS中的大多数事件处理几乎都是围绕魔法字符串构建的,所以我觉得这很正常)。动态对象感觉有点反TS(这是一个悖论,因为JS当然是围绕它们构建的),我将把上面的类转换成一个通用的HubManager,我可以将hub名称传递到其中,然后与事件侦听器连接起来。当然,处理神奇字符串的一种方法是创建一个枚举(目前还不是TS-one,因为它们仍然是实验性的,只是一个具有静态字符串成员的类)。这就是我对Azure ServiceBus所做的,另一个基于字符串的PubSub系统,它运行得非常好。稍微有些相切,但我想你可能会感兴趣,我编写了一个T4模板,从你的中心生成.d.ts:@RobFonseca Ensor-进一步证明,任何善行都会受到惩罚:我刚刚在这篇文章中发布了我遇到的问题正在与它进行交互:-)。
///<reference path="../Scripts/jquery-1.8.d.ts" />
///<reference path="../Scripts/signalr-1.0.d.ts" />
///<reference path="ISignalR.ts" />

export module Service {
    export var roomHub = $.connection.roomHub;
}
export class FrameworkHub {

    private connection: HubConnection;
    private proxy: HubProxy;

    Init(): void {
        this.Connected = false;
        this.connection = $.hubConnection();
        this.connection.logging = true;
        // Binding with createHubProxy means you can use a string name, so no need to add dynamic properties to the hub
        this.proxy = this.connection.createHubProxy("MyHubName"); 
        this.wireEventListeners();
        this.initializeConnection();
    }

    // Binding with proxy.on means you can use a string name for the function, so no need to add dynamic properties to the hub.
    wireEventListeners(): void {
        this.proxy.on("HandleFrameworkMessage", (message: IFrameworkMessage) => {
            console.log("HandleFrameworkMessage: " + message.AccountID + " - " + message.ArmID);
            // Do something to handle the message here.
        });
    }

    initializeConnection(): void {
        //console.log("Framework Hub initializeConnection");
        var that = this;
        //Again, using invoke means passing a string argument.
        this.connection.start().done(() => {
            that.proxy.invoke("Connect", this.AccountID, this.ArmID).done((response:FrameworkHubResponse) => {
                //console.log("FHR: " + response.Success + " - " + response.Message);
                if (response.Success) {
                    // Do something.
                }
                else {
                    // Try again. Would be better with some kind of exponential back-off.
                    setTimeout(that.initializeConnection, 500);
                }
            });
        });
    }
}