如何为具有构造函数(如imap)的复杂外部commonjs模块编写TypeScript声明文件



这个问题是我前面一个问题的改进:如何为具有构造函数的外部commonjs模块编写TypeScript声明文件?

我正在尝试为imap模块编写一个声明文件:-关于npm的imap-节点imap这个文件应该是什么样子的?

在没有找到一个令人满意的答案,我原来的问题上面,我意识到有一些竞争的特点的语言:

  • 任何导出或导入都会使模块成为外部模块
  • 似乎没有办法从具有(模块级)构造函数的外部模块导出多个实体,因此共享实体必须在模块(环境)之外
    请参阅我之前的问题(如上)
  • 无法将外部模块导入声明模块之外的声明文件
    不允许使用以下模式: import fs = require('fs'); declare module 'A' {}

以下是到目前为止我对申报文件的了解:

interface IIMAPAccount {
    user:           string;
    password:       string;
    host:           string;
    port:           number;
    tls?:           boolean;
}
interface IEMail {
    mail:            any;
}
interface ICriteria {
    // The following message flags are valid types that do not have arguments:
    ALL:            void;    // All messages.
    ANSWERED:       void;    // Messages with the Answered flag set.
    DELETED:        void;    // Messages with the Deleted flag set.
    DRAFT:          void;    // Messages with the Draft flag set.
    FLAGGED:        void;    // Messages with the Flagged flag set.
    NEW:            void;    // Messages that have the Recent flag set but not the Seen flag.
    SEEN:           void;    // Messages that have the Seen flag set.
    RECENT:         void;    // Messages that have the Recent flag set.
    OLD:            void;    // Messages that do not have the Recent flag set. This is functionally equivalent to "!RECENT" (as opposed to "!NEW").
    UNANSWERED:     void;    // Messages that do not have the Answered flag set.
    UNDELETED:      void;    // Messages that do not have the Deleted flag set.
    UNDRAFT:        void;    // Messages that do not have the Draft flag set.
    UNFLAGGED:      void;    // Messages that do not have the Flagged flag set.
    UNSEEN:         void;    // Messages that do not have the Seen flag set.
    // The following are valid types that require string value(s):
    BCC:            any;    // Messages that contain the specified string in the BCC field.
    CC:             any;    // Messages that contain the specified string in the CC field.
    FROM:           any;    // Messages that contain the specified string in the FROM field.
    SUBJECT:        any;    // Messages that contain the specified string in the SUBJECT field.
    TO:             any;    // Messages that contain the specified string in the TO field.
    BODY:           any;    // Messages that contain the specified string in the message body.
    TEXT:           any;    // Messages that contain the specified string in the header OR the message body.
    KEYWORD:        any;    // Messages with the specified keyword set.
    HEADER:         any;    // Requires two string values, with the first being the header name and the second being the value to search for. If this second string is empty, all messages that contain the given header name will be returned.
    // The following are valid types that require a string parseable by JavaScripts Date object OR a Date instance:
    BEFORE:         any;    // Messages whose internal date (disregarding time and timezone) is earlier than the specified date.
    ON:             any;    // Messages whose internal date (disregarding time and timezone) is within the specified date.
    SINCE:          any;    // Messages whose internal date (disregarding time and timezone) is within or later than the specified date.
    SENTBEFORE:     any;    // Messages whose Date header (disregarding time and timezone) is earlier than the specified date.
    SENTON:         any;    // Messages whose Date header (disregarding time and timezone) is within the specified date.
    SENTSINCE:      any;    // Messages whose Date header (disregarding time and timezone) is within or later than the specified date.
    //The following are valid types that require one Integer value:
    LARGER:         number;    // Messages with a size larger than the specified number of bytes.
    SMALLER:        number;    // Messages with a size smaller than the specified number of bytes.
    // The following are valid criterion that require one or more Integer values:
    UID:            any;    // Messages with UIDs corresponding to the specified UID set. Ranges are permitted (e.g. '2504:2507' or '*' or '2504:*').
}
interface IFetchOptions {
    markSeen:       boolean;  // Mark message(s) as read when fetched. Default: false
    struct:         boolean;  // Fetch the message structure. Default: false
    envelope:       boolean;  // Fetch the message envelope. Default: false
    size:           boolean;  // Fetch the RFC822 size. Default: false
    modifiers:      any;      // Fetch modifiers defined by IMAP extensions. Default: (none)
    bodies:         any;      // A string or Array of strings containing the body part section to fetch. Default: (none) Example sections:
}
declare module "imap" {
    import events                           = require('events');
    import EventEmitter                     = events.EventEmitter;
    interface IMAPFetch extends EventEmitter {
    }
    class IMAP extends EventEmitter {
        constructor(account : IIMAPAccount);
        connect();
        openBox(name : string, flag : boolean, cb : (err : Error, box) => void);
        search(criteria : ICriteria, cb : (error : Error, uids : string[]) => void);
        fetch(source : any, object : IFetchOptions) : IMAPFetch;
    }
    var out: typeof IMAP;
    export = out;
}

理想情况下,所有的接口都将在模块"imap"内部定义,因此没有全局范围的污染。

理想情况下,所有接口都将在模块"imap"内部定义,因此不会污染全局范围的

代替:

interface IFetchOptions {
    markSeen:       boolean;
    // so on
}
interface ICriteria {        
    ALL:            void;
}

执行以下

module imap {
    interface IFetchOptions {
        markSeen:       boolean;
        // so on
    }
    interface ICriteria {        
        ALL:            void;
    }
}

imap只会污染全球范围。这是一个未初始化的模块,只能用于类型信息。

参考:查看重影模块:http://definitelytyped.org/guides/best-practices.html

在继续研究这个问题后,我已经编写了定义文件,但仍然没有找到将所有接口放在模块内部的方法,以避免全局范围的污染。

我在一个拉取请求中向确定性类型提交了定义文件,您可以在这里查看:https://github.com/psnider/DefinitelyTyped/commit/460bb6d63e349918b20e49d7a62f3d2a7c2aea0a


已编辑

感谢basarat为我指明了正确的方向,尽管我无法将其缝合在一起,直到我发现了更多缺失的部分。

我查看了其他答案和定义文件,发现了一种似乎有效的方法,并更新了我的拉取请求:https://github.com/borisyankov/DefinitelyTyped/pull/3324

我在imap.d.ts:中使用了此模式

declare module IMAP {
    export interface Config {}
    export class Connection {
        constructor(config : Config);
    }
}
declare module "imap" {
    var out: IMAP.Connection;
    export = out;
}

其中IMAP是一个未初始化的模块,正如basarat所建议的,它使接口可以在IMAP命名空间中访问。

然后在使用imap模块的代码中,示例.ts

/// <reference path='imap.d.ts' />   // brings module IMAP into scope
import Imap = require('imap');       // gets the connection class
var conn = new Imap({/* omitted for brevity*/});  // creates an imap connection

最新更新