2012-11-26 103 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