簡體   English   中英

我如何在 Typescript 中聲明一個 Generic Promise,以便當 Generic 類型為“<void> ”,它的一個方法不會帶參數?

[英]How do I declare a Generic Promise in Typescript, so that when the Generic type is “<void>”, one of its methods won't take a parameter?

在 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();
}

我見過的所有承諾定義文件都聲明承諾的“解決”方法必須接受一個值。 是最近的一個來自奇妙的絕對類型項目的例子:

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

``

這基本上是說,“解析回調必須傳遞一個 R 類型的值。” 這對於像new Promise<number>這樣的承諾來說很好。 Typescript 將驗證我們正在使用number類型的值調用 resolve。

但是,如果我想要一個沒有值的承諾,所以我希望能夠在不傳遞值的情況下調用 resolve() 呢? 我可以這樣聲明我的承諾: new Promise<void>但是我仍然被迫調用 resolve 並傳入某種值。 我可以調用resolve(undefined) ,但這讀起來有點奇怪。

似乎沒有辦法在 Typescript 中正確捕捉這個概念:“如果這個泛型的類型是‘void’,那么不要期望這個函數有一個參數。”

我能做的最接近的是在 resolve 方法中將結果標記為可選,但這意味着結果始終是可選的,即使對於 Promise 的類型版本也是如此。

這確實有效!
承諾定義更新以支持此類用例。

Runnable 示例太長,無法發布。 但是只需將最新的定義和您的 Promise 代碼復制/粘貼到編輯器中,您就會看到您的示例現在可以工作了。

從您想要使用 Promise 接口的方式來看,您似乎希望有時傳遞一個值,有時您不想傳遞任何值,這就是可選參數的用途。 如果解決帶有“未定義”結果的承諾是不可接受的(IMO 這不是一個壞主意,這確切地說明了代碼中發生的事情 - 承諾的結果udefined)我可以提出一個似乎就是你的解決方案尋找:

我會為承諾定義一個“合同”,讓我們說:

export interface IMyPromiseResult {
    result: number;
}

並將其與承諾一起使用:

new Promise<IMyPromiseResult>((resolve)=>{

   resolve(<IMyPromiseResult>{ result: 5 });

   resolve(<IMyPromiseResult>{ });
}

雖然這種方法有點復雜,但它打開了一些有趣的選項......另一方面 - 當前的絕對類型 Promise 構造函數定義為:

constructor(callback: (resolve: (result?: R) => void, reject: (error: any) => void) => void);

所以有一個可選的結果是允許的,你應該沒問題。

可能剛剛想出了一個我滿意的解決方法。 在這里我想有一個的情況下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);
    }
}

在這種情況下,我可以像這樣使用它:

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

當然,開發人員將不得不使用 VoidPromise 而不是簡單的“Promise”,但無需錯誤地將 resolve 參數標記為可選參數即可實現預期效果。

對於我的場景,上面的代碼比將所有resolve方法標記為具有可選結果更符合我的期望。 在 99% 的情況下,將所有結果標記為可選的感覺很危險。 如果它總是可選的,我可以聲明一個Promise<number> ,在沒有結果的情況下調用resolve() ,並為我的承諾獲得一個undefined結果。 在那種情況下,我應該拒絕承諾。 我不相信解析方法的參數是真正可選的。 (來源: https : //github.com/domenic/promises-unwrapping#the-promise-constructor

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM