如何导入类型定义模块? (错误TS2656:......不是模块)

时间:2016-06-14 18:35:05

标签: typescript

我有一个简单的npm模块emitter20,我正在尝试添加类型定义。以下是其来源的所有20行:

module.exports = function() {
  var subscribers = []
  return {
    on: function (eventName, cb) {
      subscribers.push({
        eventName: eventName,
        cb: cb
      })
    },
    trigger: function (eventName, data) {
      subscribers
        .filter(function (subscriber) {
          return subscriber.eventName === eventName
        })
        .forEach(function (subscriber) {
          subscriber.cb(data)
        })
    }
  }
}

这是emitter20项目根目录中的index.d.ts文件:

declare module 'emitter20' {
  interface IEmitter {
    on: (eventName: string, cb: (data?: any) => void) => void;
    trigger: (eventName: string, data?: any) => void;
  }
  interface EmitterFactory {
    new(): IEmitter;
  }
  export = IEmitter;
}

我也试过这个:

declare module 'emitter20' {
  export interface IEmitter {
    on: (eventName: string, cb: (data?: any) => void) => void;
    trigger: (eventName: string, data?: any) => void;
  }
  export interface EmitterFactory {
    new(): IEmitter;
  }
}

我尝试将它导入我的项目中:

import IEmitter = require('emitter20')

export interface SwapManager extends IEmitter {
  manager: any;
}

但是我收到以下错误:

error TS2656: Exported external package typings file './node_modules/emitter20/index.d.ts' is not a module. Please contact the package author to update the package definition.

如何定义和导入emitter20模块的类型定义?

(旁白:打字稿导入/导出...一个学习曲线的地狱!)

1 个答案:

答案 0 :(得分:2)

这里的问题是,这不是一个适当的" JS模块并被警告它实际上并没有实际暴露任何类型,因此你将无法将其子类化......我认为。

如果这是一个"正常"(?)或ES6 JS模块,它们返回了类等,你只需要像你尝试的那样只使用一堆export this; export that; export default function factory(),但这是其中一个函数和export =模块在​​我的方法中使用,记录为:

  

为了向后兼容CommonJS和AMD风格模块,   TypeScript还支持表单导出的export-equals声明   =点。与默认导出声明不同,默认导出声明只是名为default的导出的简写,export-equals声明指定一个   要导出的实体代替实际模块。

我知道以下两种方法可以获得这种"输入":

方法1:使用接口:

优点:

  • 为您提供智能感知/自动完成功能并输入安全性

缺点:

  • 不公开显式类型声明的接口(您不能声明具有该类型的变量)

<强> main.ts

import * as emitterFactory from 'emitter20';

var emitterInstance = emitterFactory();
emitterInstance.on(...)

<强> types.d.ts

declare module 'emitter20' {
    interface IEmitter {
        on: (eventName: string, cb: (data?: any) => void) => void;
        trigger: (eventName: string, data?: any) => void;
    }

    interface IEmitterFactory {
        (): IEmitter;
    }

    var EmitterFactory : IEmitterFactory;

    export = EmitterFactory;
}

方法2:具有相同名称的函数+命名空间

优点:

  • 为您提供智能感知/自动完成功能并输入安全性
  • 公开界面

缺点:

  • 看起来有点像黑魔法? :)

<强> main.ts

import * as emitter from 'emitter20';

var emitterInstance : emitter.IEmitter = emitter();
emitterInstance.on("event", (data : any) => {
    console.log(data.foo);
})
emitterInstance.trigger("event", {"foo": "bar"});

<强>输出:

bar

<强> types.d.ts

declare module 'emitter20' {

    function Emitter(): Emitter.IEmitter;
    namespace Emitter {
        interface IEmitter {
            on: (eventName: string, cb: (data?: any) => void) => void;
            trigger: (eventName: string, data?: any) => void;
        }
    }


    export = Emitter;
}

方法3:声明全局命名空间

优点:

  • 为您提供智能感知/自动完成功能并输入安全性
  • 公开界面
  • 看起来不像是黑魔法

缺点:

  • Emitter命名空间变为全局且在任何地方都可见(全局环境声明)

<强> main.ts

import * as emitter from 'emitter20';

var emitterInstance : Emitter.IEmitter = emitter();

<强> types.d.ts

declare namespace Emitter
{
    export interface IEmitter {
        on: (eventName: string, cb: (data?: any) => void) => void;
        trigger: (eventName: string, data?: any) => void;
    }

    export interface IEmitterFactory {
        (): Emitter.IEmitter;
    }
}

declare module 'emitter20' {
    var EmitterFactory : Emitter.IEmitterFactory;

    export = EmitterFactory;
}