简体   繁体   English

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

[英]Exporting a TypeScript module results in interfaces not getting picked up

I'm using TypeScript and SignalR together, and am trying to define static types for the generated SignalR classes. 我一起使用TypeScript和SignalR,并且我正在尝试为生成的SignalR类定义静态类型。 And if I do something like this, it works: 如果我做这样的事情,它的工作原理:

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

And of course $.connection is of type SignalR , which is defined in the file "signalr-1.0.d.ts", and extended in the file above. 当然$.connection SignalRSignalR类型,它在文件“signalr-1.0.d.ts”中定义,并在上面的文件中扩展。

However, I need to be able to reference the Service module from other files, so I need to add the "export" keywords to both the module and the interface, ie: 但是,我需要能够从其他文件引用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 { }
}

However, when I do that, I get a little red squiggly line under $.connection.roomHub , and the compiler returns the error, "The property 'roomHub' does not exist on type SignalR." 但是,当我这样做时,我在$.connection.roomHub下得到一条红色的小红线,并且编译器返回错误,“属性'RoomHub'在SignalR类型上不存在。”

I certainly don't understand everything about TypeScript, but that doesn't seem right to me. 我当然不了解TypeScript的所有内容,但这对我来说似乎并不合适。 Have I run into a compiler bug? 我遇到了编译器错误吗? Or is there a different way to do this? 或者有不同的方法来做到这一点?

I was able to figure out a workaround. 我找到了一个解决方法。 I pulled out the interfaces into a separate file: 我将接口拉出到一个单独的文件中:

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

interface RoomHub {
}

And then I referenced that file in my Service file 然后我在我的服务文件中引用了该文件

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

And that works, oddly enough. 这很有效,奇怪的是。 I'm not sure if it's a compiler bug, or something I'm continuing to misunderstand, but it clearly has something to do with some subtle semantic changes related to the AMD module support. 我不确定这是一个编译器错误,还是我继续误解的东西,但它显然与一些与AMD模块支持相关的细微语义变化有关。 I'd love to hear more of an explanation from someone who groks TypeScript and/or RequireJS modules a little better than I do. 我很想听到更多来自那些比我更好地理解TypeScript和/或RequireJS模块的人的解释。

If the SignalR object has actual members, you want to use the declare module syntax instead. 如果SignalR对象具有实际成员,则需要使用declare module语法。 interface declarations only describe members on types (rather than describing extant objects). 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 { }
}

There is more than one way to wire SignalR up, and using createHubProxy and invoke are more TypeScript friendly: 连接SignalR的方法不止一种,使用createHubProxyinvoke更适合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);
                }
            });
        });
    }
}

That's a slightly rough example cut from real code, but I've found it the best TS way to use SignalR. 这是一个从实际代码中略微粗略的例子,但我发现它是使用SignalR的最佳TS方式。 Docs for this kind of connection are here: https://github.com/SignalR/SignalR/wiki/SignalR-JS-Client-Hubs-%28No-Proxy%29 - watch out because the Docs haven't always kept pace with the recent changes. 这种连接的文档在这里: https//github.com/SignalR/SignalR/wiki/SignalR-JS-Client-Hubs-%28No-Proxy%29 - 小心,因为文档并不总是跟上最近的变化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM