2017-09-26 256 views
0

比方說,我有以下的(最新)封裝的打字稿項目:普通函數和異步函數返回的Promise類型是否有區別?

現在,讓我們在我的項目說我定義它返回一個承諾(以打字稿的原生環境聲明的定義)的函數:

import * as q from "q"; 

function doSomethingElseAsync(): Promise<number> { 
    return q.Promise<number>((resolve, reject) => { 
     setTimeout(() => resolve(1), 5000); 
    }); 
} 

編譯時,打字稿抱怨,出現以下錯誤:

error TS2322: Type 'Q.Promise<number>' is not assignable to type 'Promise<number>'. 
    Types of property 'then' are incompatible. 
    Type '<U>(onFulfill?: ((value: number) => IWhenable<U>) | undefined, onReject?: ((error: any) => IWhena...' is not assignable to type '<TResult1 = number, TResult2 = never>(onfulfilled?: ((value: number) => TResult1 | PromiseLike<TR...'. 
     Types of parameters 'onFulfill' and 'onfulfilled' are incompatible. 
     Type '((value: number) => TResult1 | PromiseLike<TResult1>) | null | undefined' is not assignable to type '((value: number) => IWhenable<TResult1 | TResult2>) | undefined'. 
      Type 'null' is not assignable to type '((value: number) => IWhenable<TResult1 | TResult2>) | undefined'. 

有一段時間,我認爲這是因爲Q的承諾只是沒有用的打字稿的本地聲明兼容。但是,如果我將async關鍵字添加到函數定義中,則錯誤完全消失。

我對這種行爲很困惑。這是Typescript,Q還是Q類型的錯誤?或者,這是一些深奧的,但預期的編譯器行爲?

+2

可能相關? https://開頭計算器。com/questions/42689713/es6-promise-typescript-and-the-bluebird-promise基本上......承諾不是本地承諾。就像藍鳥承諾不是本地承諾。 –

+0

只要它適合Typescript期望的界面,無論它是否是本地承諾都沒關係。 Q和Bluebird承諾在實踐中運作良好。 – Craxal

+0

對,但更重要的是,它們是否匹配界面?我不認爲他們這樣做。 –

回答

0

我的猜測是,將async關鍵字添加到你的函數會導致Javascript將該函數的返回值包裝在本地Promise中,以便函數返回一個promise還是一個值,結果將是一個promise是await ed。

例如,它會做這樣的事情:

Promise.resolve().then(() => doSomethingElseAsync()) 

沒有async關鍵字,你返回q承諾,這不是本地人Promise一個實例,所以你得到一個輸入錯誤。

我相信它會工作得很好像這樣以及(與q刪除):

function doSomethingElseAsync(): Promise<number> { 
    return Promise<number>((resolve, reject) => { 
     setTimeout(() => resolve(1), 5000); 
    }); 
} 

或者,如果您的環境中不包括本地Promise類,也許改變的返回類型可能會奏效,像這樣的:

function doSomethingElseAsync(): q.Promise<number> { 
    return q.Promise<number>((resolve, reject) => { 
     setTimeout(() => resolve(1), 5000); 
    }); 
} 
+0

在本地承諾中包裝返回值聽起來更像是異步/等待的實現細節。一旦JavaScript被輸出,類型就不再被考慮。 如果我的目標是ES5,不執行原生承諾,刪除Q將不起作用。這就是爲什麼我使用像Q. – Craxal

+0

這樣的外部實現我更新了一個潛在的ES5解決方案的答案,以及如果您沒有本地可用的Promise – Griffin

+1

另外,是的,對不起,包裝更多的是想象如何異步/等待作品與如何解決你的問題。 – Griffin

0

它看起來像問題僅僅是Q的承諾與異步不相容/等待。

我試着將異步功能的返回類型從原生Promise更換爲q.Promise。編譯器現在給我這個錯誤:

Type '<T>(resolver: (resolve: (val?: T | PromiseLike<T> | undefined) => void, reject: (reason?: any) =>...' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value. 
    Type '<T>(resolver: (resolve: (val?: T | PromiseLike<T> | undefined) => void, reject: (reason?: any) =>...' provides no match for the signature 'new <T>(executor: (resolve: (value?: T | PromiseLike<T> | undefined) => void, reject: (reason?: any) => void) => void): PromiseLike<T>'. 

它說的返回類型「在ES5/ES3有效的異步函數的返回類型,因爲它並不是指一個無極兼容的構造函數值是沒有的。」這是有道理的,因爲q.Promise不是一個構造函數,你可以調用new。相比之下,其他承諾實現(如Bluebird)具有兼容的構造函數。