TypeScript调用签名问题

时间:2016-04-12 08:49:03

标签: typescript

我有档案my-module.ts

declare module "my-module" {
    interface main {
        (string):string,
        methodName():any,
        propertyName:any,
        objectName:Object
    }
    export default main;
}

并在文件test.ts中使用时:

import * as MyModule from "my-module";
var s = MyModule('test');

我收到错误Cannot invoke an expression whose type lacks a call signature.

为什么会这样,以及如何解决?

更新

根据Joe Clay的建议,如果我们将代码更改为:

declare module "my-module" {
    interface main {
        (string):string,
        methodName():any,
        propertyName:any,
        objectName:Object
    }
    var myModule: main;
    export default myModule;
}

然后尝试使用它:

import myModule from "my-module";
var s = myModule('test');

它会生成以下JavaScript:

var my_module_1 = require("my-module");
var s = my_module_1["default"]('test');

引发错误my_module_1.default is not a function

更新

以下更改解决了当前问题:

declare module "my-module" {
    interface main {
        (string):string,
        methodName():any,
        propertyName:any,
        objectName:Object
    }
    var myModule: main;
    export = myModule; // <= Here's the change
}

并使用它:

import * as myModule from "my-module";

然而,这给我带来了另一个问题。我展示了一个my-module的简化示例,而真正的一个有几个类,enum - s要导出。但是,如上所述,我们不再能做到这一点。

环境类和enum - s应该使用export enum Name{}export class Name导出,但在使用export = myModule时不允许使用此语法,从而产生错误:{ {1}}。

现在如何纠正这个? :)

更麻烦的是,我有另一个具有An export assignment cannot be used in a module with other exported elements.类型属性的模块,如果我声明为my-module,我将获得properName: MyModule。我不明白这意味着什么。

1 个答案:

答案 0 :(得分:2)

a)如果您有默认导出,导入语法只是import MyModule from "my-module"; - 您不需要* as

b)您无法呼叫接口。您可以调用实现的内容,但尝试执行MyModule()并不合理。

修改

响应更新的代码 - this is a pretty common issue when you're trying to use TypeScript's ES6 imports with a CommonJS module。微软坚持在可能的情况下坚持使用规范,而不是使用任何魔法将module.exports转换为ES6默认导出 - 技术上他们可能在这样做时是正确的,但考虑到Babel (可能是最流行的JavaScript转换器)转换就好了,我真的希望他们也可以将它添加到TypeScript中。

建议的方法是将导入恢复为import * as MyModule from "my-module";语法并修改声明,如下所示:

declare module "my-module" {
    interface main {
        (string):string,
        methodName():any,
        propertyName:any,
        objectName:Object
    }
    var myModule: main;
    export = myModule; // <= Here's the change
}

希望能够为您提供您正在寻找的结果。

编辑2:

当您想要在声明中开始定义自己的类型时,它会变得更复杂,而不仅仅是原语 - 但不是太复杂。一个很好的例子是the type definitions for body-parser。我不会在这里复制整件事,因为我的答案已经变得很疯狂,但需要注意的是:

  • 您可以声明namespace,将其作为主要导出,然后从中导出其他内容。
  • 可以合并&#39;声明 - 在我链接的文件中,注意它们将bodyParser定义为函数,然后定义具有相同名称的命名空间。这些将合并,这意味着命名空间中的导出将显示为函数的属性(例如bodyParser()bodyParser.json()都可用)。

基本上,我能给你的最好建议是浏览DefinitelyTyped存储库,找到你熟悉的模块,看看他们的定义是如何创建的 - 这是学习如何自己完成的最好方法。