我一起使用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
的类型为SignalR
,它在文件“signalr-1.0.d.ts”中定义,并在上面的文件中进行了扩展。
但是,我需要能够从其他文件中引用Service
模块,因此我需要在模块和接口中添加“export”关键字,即:
///<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的所有内容,但这对我来说似乎并不合适。我遇到了编译器错误吗?或者有不同的方法来做到这一点?
答案 0 :(得分: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模块的人的解释。
答案 1 :(得分: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 { }
}
答案 2 :(得分:2)
连接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方式。这种联系的文档在这里:https://github.com/SignalR/SignalR/wiki/SignalR-JS-Client-Hubs-%28No-Proxy%29 - 请注意,因为文档并不总是跟上最近的变化。