简体   繁体   English

打字稿:无法导出通用接口模块并包含其他通用接口

[英]Typescript: Cannot export a module that is a generic interface and contains other generic interfaces

I'm trying to write a CommonJS declaration file for Bluebird, a promise library that directly exports a generic Promise class. 我正在尝试为Bluebird编写一个CommonJS声明文件,这是一个直接导出通用Promise类的promise库。 However, the library also exports several other generic classes as static members (PromiseInspection), and it seems like its impossible to model this with typescript. 但是,该库还将几个其他泛型类导出为静态成员(PromiseInspection),并且似乎无法使用typescript对其进行建模。

Edit: Usage example, to illustrate how the module's exported class works: 编辑:用法示例,用于说明模块的导出类的工作方式:

import Promise = require('bluebird');
var promise:Promise<number> = Promise.cast(5);
var x:Promise.PromiseInspection<number> = promise.inspect();

I tried several strategies - simplified examples follow: 我尝试了几种策略 - 简化示例如下:

1. The obvious way 1.显而易见的方式

declare module "bluebird" {
    class PromiseInspection<T> {
        // ...
    }
    class Promise<T> {
        PromiseInspection: typeof PromiseInspection; // error
        constructor<T>();
        inspect():PromiseInspection<T>; // error
        static cast<U>(value:U):Promise<U>; 
        // ...
    }
    export = Promise;
}

Fails with the error unable to use private type PromiseInspection as a public property 失败,错误无法使用私有类型PromiseInspection作为公共属性

2. Using a static interface 2.使用静态接口

declare module "bluebird2" {
    interface PromiseInspection<T> {
        // ...  
    }
    interface Promise<T> {
        constructor<T>();
        inspect():PromiseInspection<T>;
    }
    interface PromiseStatic {
        new<T>();
        PromiseInspection:typeof PromiseInspection;
        cast<U>(value:U):Promise<U>; // error
    }
    export = PromiseStatic;
}

Also fails similarly, but this time the private type is Promise 同样失败,但这次私有类型是Promise

3. Trying to directly export a constructor function from the module 3.尝试从模块直接导出构造函数

declare module "bluebird3" {
    export interface PromiseInspection<T> {
        // ...
    }
    export interface Promise<T> {
        constructor<T>();
        inspect():PromiseInspection<T>;
    }

    export new<T>(); // syntax error
    export function cast<U>(value:U):Promise<U>; 
}

This almost works, except of course its impossible to a constructor function that way. 这几乎可以工作,当然除了这样的构造函数不可能。

4. The namespace polluting way (Works, with downsides) 4.命名空间污染方式(Works,有缺点)

interface PromiseInspection<T> {
    // ...
}
interface Promise<T> {
    constructor<T>();
    inspect():PromiseInspection<T>;
}

declare module "bluebird4" {    
    interface PromiseStatic {
        new<T>():Promise<T>;
        PromiseInspection: typeof PromiseInspection;
        cast<U>(value:U):Promise<U>;
    }
    export = PromiseStatic;
}

Works, but it pollutes the global namespace with both Promise and PromiseInspection. Works,但它使用Promise和PromiseInspection污染全局命名空间。 This might be okay but I'd rather avoid it as in CommonJS its usually considered unacceptable. 可能没问题,但我宁愿避免使用它,因为在CommonJS中它通常被认为是不可接受的。

5. With declaration merging (gets me 90% of the way...) 5.声明合并(让我90%的方式...)

declare module "bluebird5" {
    module Promise {
        export interface PromiseInspection<T> {
            value(): T;
            // ...
        }
        export
        function cast<U>(value: U): Promise<U> ;
    }

    class Promise<T> {
        new <T> (): Promise <T> ;
        inspect(): Promise.PromiseInspection <T> ;
    }

    export = Promise;
}

Almost there - except that now I'm not allowed to replace class Promise<T> with interface Promise<T> , making Promise<T> unextendable. 差不多了 - 除了现在我不允许用interface Promise<T>替换class Promise<T> interface Promise<T> ,使Promise<T>无法实现。 If I try to do it, the following code: 如果我尝试这样做,请使用以下代码:

import Promise = require('bluebird');
var x = new Promise<number>();
x.inspect().value().toExponential();

fails with the error "Invalid 'new' expression" 失败并显示错误“无效'新'表达式”

Link to the actual, work-in-progress bluebird.d.ts - this one currently pollutes the global namespace (uses solution 4) 链接到实际的,正在进行中的bluebird.d.ts - 这个当前污染全局命名空间(使用解决方案4)

Is there a better way to do this, or did I hit a language limitation? 有没有更好的方法来做到这一点,还是我遇到了语言限制?

Anders Hejlsberg posted an answer on CodePlex, so I'm going to add it here. Anders Hejlsberg在CodePlex上发布了一个答案,所以我将在这里添加它。 The declaration merging solution was close - but I also needed a "var" declaration to declare the static interface as it is the only one that can accept a constructor function. 声明合并解决方案很接近 - 但我还需要一个“var”声明来声明静态接口,因为它是唯一可以接受构造函数的接口。

declare module "bluebird" {
    module Promise {
        export interface PromiseInspection<T> {
            value(): T;
        }
    }
    interface Promise<T> {
        inspect(): Promise.PromiseInspection <T> ;
    }

    var Promise: {
        new<U>(): Promise<U>;
        cast<U>(value: U): Promise<U> ;
    }
    export = Promise;
}

So basically: 所以基本上:

  • interface members in the module declaration (as long as they declare just types ie non-physical) 模块声明中的接口成员(只要它们声明只是非物理类型)
  • instance members in the main interface 主界面中的实例成员
  • static function members, the constructor and other "physical" members in the var declaration. var声明中的静态函数成员,构造函数和其他“物理”成员。

Also, his comment: 他的评论:

Writing it this way you have a separate declaration for each of the three meanings of the identifier Promise: As a namespace (a module containing only types), as a type (that happens to be generic), and as a value. 通过这种方式编写,您可以为标识符Promise的三个含义中的每一个单独声明:作为命名空间(仅包含类型的模块),作为类型(恰好是通用的),以及作为值。

Looking at your code I noticed you were missing a few export statements. 看看你的代码,我注意到你缺少一些export语句。 The code below compiles - would it suit? 下面的代码编译 - 它适合吗?

declare module bluebird {
    export class PromiseInspection<T> {
        // ...
    }
    export class Promise<T> {
        constructor<T>();
        inspect():PromiseInspection<T>;
        static all<T>(promises:Promise<T>[]):Promise<T[]>;
    }
}

declare module "bluebird" {
    export = bluebird;
}

Though I generally favour using interfaces when defining typings as in #2: 虽然我通常喜欢在#2中定义输入时使用接口:

declare module bluebird {
    export interface PromiseInspection<T> {
        // ...
    }
    export interface Promise<T> {
        constructor<T>();
        inspect():PromiseInspection<T>;
    }
    export interface PromiseStatic {
        new<T>();
        all<T>(promises:Promise<T>[]):Promise<T[]>;
    }
}

declare module "bluebird" {
    export = bluebird;
}

Failing that have you tried using another promises library as the basis for your typings? 如果没有你尝试使用另一个promises库作为你的打字基础? You could do worse than look at https://github.com/borisyankov/DefinitelyTyped/blob/master/q/Qdts 你可能会比看看https://github.com/borisyankov/DefinitelyTyped/blob/master/q/Qdts更糟糕

Roughly speaking they look a little like this: 粗略地说他们看起来有点像这样:

declare function Q<T>(promise: Q.IPromise<T>): Q.Promise<T>;
declare function Q<T>(promise: JQueryPromise<T>): Q.Promise<T>;
declare function Q<T>(value: T): Q.Promise<T>;

declare module Q {
    //… functions etc in here
}

declare module "q" {
    export = Q;
}

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

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