如何在Typescript中声明Generic Promise,以便当Generic类型为"<void>"时,其中一个方法不会采用参数?

Tay*_*tay 10 typescript definitelytyped

在Typescript中,我希望能够以这样的方式定义Promise的类型,以便我可以这样做:

//This works today:
new Promise<number>((resolve)=>{
   //Cool
   resolve(5);
   //Error, because I didn't pass a number:
   resolve();
}

//This is what I want to do also:
new Promise<void>((resolve)=>{
   //Error, because I passed a value:
   resolve(5);
   //Cool, because I declared the promise to be of type void, so resolve doesn't take a value:
   resolve();
}
Run Code Online (Sandbox Code Playgroud)

我见过的promise定义文件都声明promise的"resolve"方法必须带一个值.以下是精彩的DefinitelyTyped项目的最新示例:

declare class Promise<R> implements Thenable<R> {
    constructor(callback: (resolve : (result: R) => void, reject: (error: any) => void) => void); 
///...
}
Run Code Online (Sandbox Code Playgroud)

```

这基本上说,"解析回调必须传递一个R类型的值".对于像这样的承诺来说这很好new Promise<number>.Typescript将验证我们是否使用类型值调用resolve number.

但是,如果我想要一个没有值的promise,那么我希望能够在不传递值的情况下调用resolve()?我可以这样声明我的承诺:new Promise<void> 但是我仍然被迫调用resolve并传入某种值.我可以打电话resolve(undefined),但这听起来有点奇怪.

似乎无法在Typescript中正确捕获此概念:"如果此泛型具有'void'类型,则不要指望此函数的参数."

我能做的最接近的是在resolve方法中将结果标记为可选,但这意味着结果始终是可选的,即使对于Promises的类型化版本也是如此.

And*_*ers 5

这确实有效!
承诺的定义进行了更新,以支持这样的用例。

Runnable 示例太长,无法发布。但是只需将最新的定义和您的 Promise 代码复制/粘贴到编辑器中,您就会看到您的示例现在可以工作了。

  • 您提供的链接现已损坏。 (7认同)

Tay*_*tay 2

可能刚刚想出了一个令我满意的解决方法。如果我想要Promise<void>确保resolve回调不参数,而不是让解析方法始终带可选参数,我可以定义一个新类,如下所示:

export class VoidPromise extends RSVP.Promise<void>{
    //Note that resolve does not take a parameter here:
    constructor(callback:(resolve:() => void, reject:(error:any) => void) => void){
        super(callback);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我可以像这样使用它:

    public static testVoidPromise() : VoidPromise{
        return new VoidPromise((resolve, reject)=>{

            setTimeout(1000, ()=>{
                if (Math.random() < 0.5){
                    //Note that resolve() does NOT take a parameter
                    resolve();
                }else{
                    reject(new Error("Something went wrong"));
                }
            })
        });
    }
Run Code Online (Sandbox Code Playgroud)

当然,开发人员必须使用 VoidPromise 而不是简单的“Promise”,但无需错误地将解析参数标记为可选就可以达到预期效果。

对于我的场景,上面的代码比将所有 resolve方法标记为具有可选结果更符合我的期望。在 99% 的情况下,将所有结果标记为可选感觉很危险。如果它始终是可选的,我可以声明一个,没有结果的Promise<number>调用,并为我的承诺获得一个结果。既然如此,我就应该拒绝这个承诺。我不认为解析方法的参数是真正可选的。(来源:https ://github.com/domenic/promises-unwrapping#the-promise-constructor )resolve()undefined