2012-11-26 70 views
3

我一起使用TypeScript和SignalR,并试图为生成的SignalR类定义静态类型。如果我做这样的事情,它的工作原理:导出TypeScript模块导致接口未被拾取

///<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并且是SignalR类型,它是在文件“signalr-1.0.d.ts”所定义,扩展文件上面的。

不过,我需要能够引用来自其他文件Service模块,所以我需要“出口”的关键字添加到模块和接口两种,即:

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

export interface SignalR { 
    roomHub: Service.RoomHub; 
} 

export module Service { 
    // Error here: "The property 'roomHub' does not exist on type SignalR." 
    export var roomHub = $.connection.roomHub; 
    export interface RoomHub { } 
} 

然而,当我这么做了,我在$.connection.roomHub下得到了一条红色的波浪线,并且编译器返回错误信息:“属性'roomHub'在类型SignalR上不存在。”

我当然不明白关于TypeScript的一切,但这对我来说并不合适。我遇到了一个编译器错误?还是有不同的方式来做到这一点?

+1

轻微的切线,但我认为你可能会感兴趣,我写了一个T4模板从你的集线器生成.d.ts:https://gist.github.com/4583549 –

+0

@ RobFonseca-Ensor - 进一步的证据没有好的行为不会受到惩罚:我只是在这个问题上发布了我所遇到的问题:-)。 –

回答

6

我能弄清楚一个解决方法。我掏出接口到一个单独的文件:

// 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; 
} 

而且这样的作品,奇怪的是。我不确定它是一个编译器错误,还是我一直在误解的东西,但显然这与一些与AMD模块支持相关的细微语义变化有关。我很乐意听到更多的人对TypeScript和/或RequireJS模块比我更好的解释。

2

如果SignalR对象具有实际成员,则您希望改为使用declare module语法。 interface声明只描述类型的成员(而不是描述现存对象)。

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

declare module SignalR { 
    var roomHub: Service.RoomHub; 
} 

export module Service { 
    // Good now 
    export var roomHub = $.connection.roomHub; 
    export interface RoomHub { } 
} 
+0

用这个确切的代码,我得到了同样的错误:'$ .connection.roomHub'上有一点红色的波浪曲线,并且消息“属性'roomHub'在类型SignalR上不存在。我认为*(我不确定)'interface'语法是否合适,因为它描述了$ .connection'对象向全世界展示的接口。 –

+0

如何声明$ .connection? –

+0

它在运行时在文件'jquery.signalR-1.0.0-alpha2.js'中定义,并在编译时在定义文件'signalr-1.0.d.ts'(https://github.com/ borisyankov/DefinitelyTyped /斑点/主/ signalr/signalr-1.0.d.ts)。 –

2

还有就是连接SignalR了不止一种方法,并使用createHubProxyinvoke更打字稿友好:

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); 
       } 
      }); 
     }); 
    } 
} 

这是一个略显粗糙的例子从实际的代码切割,但我已经找到了最好的TS使用SignalR的方式。这种连接的文档在这里:https://github.com/SignalR/SignalR/wiki/SignalR-JS-Client-Hubs-%28No-Proxy%29 - 小心,因为文档并不总是跟上最近的变化。

+0

我仍然围绕着SignalR的脑袋 - 所以你会说使用这种方法而不是自动生成的代理的好处是什么?如果我使用TS自动生成的代理,是的,我需要手动定义它们的接口 - 但我想我喜欢分离关注点,以便在控制的代码中没有任何魔术字符串。当然,理想情况下,让SignalR与JS代码一起生成TS接口是非常棒的。 –

+0

这是一个风格问题,真的。我仍然习惯于SignalR,但以这种方式工作更像是与其他任何PubSub组件一起工作(JS中的大部分事件处理都是围绕魔术字符串构建的,所以对我来说感觉很正常)。动态对象感觉有点反TS(这是一个悖论,因为JS当然是围绕它们构建的),并且我将把上面的类变成一个通用的HubManager,我可以将中心名称传入,然后只是与事件监听器连接起来。 – JcFx

+0

当然,处理魔术字符串的一种方法是创建一个枚举类型(目前不是TS类型,因为它们仍然是实验性的 - 但只是一个带有静态字符串成员的类)。这就是我使用另一个基于字符串的PubSub系统的Azure ServiceBus所做的工作,它运行得非常好。 – JcFx