如何为具有构造函数(例如imap)的复杂外部commonjs模块编写TypeScript声明文件? [英] How do I write a TypeScript declaration file for a complex external commonjs module that has constructor, such as imap?

查看:64
本文介绍了如何为具有构造函数(例如imap)的复杂外部commonjs模块编写TypeScript声明文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是我先前的问题的改进: npm上的imap - node-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"内部定义,因此不会污染全局范围.

解决方案

继续研究此问题之后,我编写了定义文件,但仍未找到将所有接口放入模块内部的方法,避免污染全球范围.

我在对DefinitelyTyped的请求中提交了定义文件,您可以在这里查看: https://github.com/psnider/DefinitelyTyped/commit/460bb6d63e349918b20e49d7a2a>


已编辑

谢谢, 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;
}

如basarat建议的那样,IMAP是未初始化的模块,它使接口可以在IMAP名称空间中访问.

然后在使用imap模块的代码 example.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

This question is a refinement of my earlier one: How do I write a TypeScript declaration file for an external commonjs module that has constructor?

I'm trying to write a declaration file for the imap module: - imap on npm - node-imap What should this file look like?

After not finding a satisfactory answer to my original question above, I realize there are some competing features of the language:

  • any export or import makes a module an external module
  • there appears to be no way to export multiple entities from an external module that has a (module-level) constructor so shared entities must be outside the module (ambient).
    See my previous question (above).
  • there is no way to import external modules into a declaration file outside of the declared module
    The following pattern is disallowed: import fs = require('fs'); declare module 'A' {}

Here is what I have for the declaration file so far:

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

Ideally, all of the interfaces will be defined inside of module "imap", so there is no pollution of the global scope.

解决方案

After continuing to investigate this problem, I have written the definition file, but still haven't found a way to put all of the interfaces inside of the module, to avoid pollution of the global scope.

I submitted the definition file in a pull request to DefinitelyTyped, and you can view it here: https://github.com/psnider/DefinitelyTyped/commit/460bb6d63e349918b20e49d7a62f3d2a7c2aea0a


EDITED

Thanks, basarat, for pointing me in the right direction, although I was unable to sew it together until I found a few more missing pieces.

I reviewed other answers and definition files and found a method that appears to work, and have updated my pull request: https://github.com/borisyankov/DefinitelyTyped/pull/3324

I used this pattern in imap.d.ts:

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

Where IMAP is a non-initializaed module, as basarat suggested, and it makes the interfaces accessible within the IMAP namespace.

Then in the code that uses the imap module, example.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

这篇关于如何为具有构造函数(例如imap)的复杂外部commonjs模块编写TypeScript声明文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆