使接口在Promise库上通用

时间:2018-08-20 08:26:47

标签: typescript definitelytyped

我正在编写es6-promise-pool的定义以添加到DefinitelyTyped中,并对the discussion at GitHub进行了一些调整。该库可以使用可选的promise参数,该参数指定用于返回的诺言的类(例如ES6-Promise的polyfill或Bluebird)。在内部,它只关心您可以call new Promise(…),因此这足以指定值的类型:

interface PromiseClass<A, P extends PromiseLike<A>> {
    new(callback: (resolve: (value?: A | P) => void, reject: (reason?: any) => void) => void): P;
}

const bar: PromiseClass<number, Bluebird<number>> = Bluebird; // OK

麻烦的是指定选项的类型:

interface Options<A, P extends PromiseLike<A>, C extends PromiseClass<A, P>> {
    promise?: C;
}

function foo<A, P extends PromiseLike<A>, C extends PromiseClass<A, P>>(options: Options<A, P, C>) { /* empty */ }

foo({ promise: Bluebird.resolve(3) });

这给了我一个错误:

Argument of type '{ promise: Bluebird; }' is not assignable to parameter of type 'Options, PromiseClass>>'.
  Types of property 'promise' are incompatible.
    Type 'Bluebird' is not assignable to type 'PromiseClass> | undefined'.
      Type 'Bluebird' is not assignable to type 'PromiseClass>'.
        Type 'Bluebird' provides no match for the signature 'new (callback: (resolve: (value?: {} | PromiseLike | undefined) => void, reject: (reason?: any) => void) => void): PromiseLike'.

(请注意,类型被推断为{}。)

如果我手动指定类型:

foo<number, Bluebird<number>, PromiseClass<number, Bluebird<number>>>({ promise: Bluebird.resolve(3) });

我收到类似的错误:

Argument of type '{ promise: Bluebird; }' is not assignable to parameter of type 'Options, PromiseClass>>'.
  Types of property 'promise' are incompatible.
    Type 'Bluebird' is not assignable to type 'PromiseClass> | undefined'.
      Type 'Bluebird' is not assignable to type 'PromiseClass>'.
        Type 'Bluebird' provides no match for the signature 'new (callback: (resolve: (value?: number | PromiseLike | undefined) => void, reject: (reason?: any) => void) => void): Bluebird'.

这里是the relevant definitions from DefinitelyTyped,当正确推断类型时应该兼容:

type Resolvable<R> = R | PromiseLike<R>;

constructor(callback: (resolve: (thenableOrResult?: Resolvable<R>) => void, reject: (error?: any) => void, onCancel?: (callback: () => void) => void) => void);

对于上下文,这是我如何使用类型(省略了不相关的方法):

declare class PromisePool<
    A,                        // the type of value returned by the source
    P extends PromiseLike<A>, // the type of Promise returned by the source
    P2 extends PromiseLike<A>, // the type of Promise specified in `options`
    C extends PromisePool.PromiseClass<A, P2> // a helper class
    > {
    constructor(
        source: IterableIterator<P> | P | (() => (P | undefined)) | A,
        concurrency: number,
        options?: PromisePool.Options<A, P2, C>
    );

    promise(): P2;
    start(): P2;
}

declare namespace PromisePool {
    interface PromiseClass<A, P extends PromiseLike<A>> {
        new(callback: (resolve: (value?: A | P) => void, reject: (reason?: any) => void) => void): P;
    }

    interface Options<A, P extends PromiseLike<A>, C extends PromiseClass<A, P>> {
        promise?: C;
    }
}

如何指定Options类型,以便:

  • 可以指定任何new个可行的承诺库(如上所述),并自动推断出类型
  • 如果未指定,则回退到Promise
  • 我可以将promise类型指定为PromisePool.promisePromisePool.start的返回值

1 个答案:

答案 0 :(得分:0)

我误用了自己的类型,因为我以为Bluebird.resolve(3)的功能与Bluebird相同,尽管我出于区分两者的目的而陷入困境。无论如何,这可行:

import Bluebird = require("bluebird");
import ES6Promise = require("es6-promise");

interface PromiseClass<A, P extends PromiseLike<A>> {
    new(callback: (resolve: (value?: A | P) => void, reject: (reason?: any) => void) => void): P;
}

interface Options<A, P extends PromiseLike<A>, C extends PromiseClass<A, P>> {
    promise?: C;
}

function foo<A, P extends PromiseLike<A>, C extends PromiseClass<A, P>>(options: Options<A, P, C>, val: A): P {
    return new options.promise((resolve, reject) => resolve(val));
}

const baz: Bluebird<number> = foo({ promise: Bluebird }, 5);
const quux: ES6Promise.Promise<number> = foo({ promise: ES6Promise.Promise }, 5);

我只需要将类作为promise的值而不是实例进行传递。