2017-01-24 39 views
3

我們仍然使用angular 1.5.8,並嘗試編寫一個函數,將長計算分解爲零件。由於承諾可以返回諾言功能鏈接,我還以爲寫它這樣的:在TypeScript中,如何定義一個返回承諾的遞歸函數

interface IResult { 
    add(s: string): void { ... } 
} 

function buildResult(): IResult { ... } 
function handleItem(s: string): string { ... } 

function doWork(data: string[]): ng.IPromise<IResult> { 
    let i = 0; 
    const result = buildResult(); 

    const process =(): ng.IPromise<IResult> => { 
     for(let start = i; i < start + 100; ++i) { 
      const item = data[i]; 
      if(!item) { 
       return $q.resolve(result); 
      } 
      result.add(handleItem(item)); 
     } 

     return $timeout(process, 20) 
    } 

    return process(); 
} 

這工作,但打字稿編譯器抱怨,因爲角$超時服務接受返回值的函數,而不是一個承諾:

TS2322:鍵入'IPromise < IPromise>'不可分配給'IPromise'類型。類型'IPromise < IResult>'中缺少屬性'add'。

有沒有一種方法來正確定義此函數中的類型?

我可以看到兩個選項去:

  1. 定義過程返回any
  2. 鑄return語句:

return $timeout(process, 20) as any as ng.IPromise<IResult>

任何更好的主意嗎?

回答

0

$超時簽名是:

interface ITimeoutService { 
    (delay?: number, invokeApply?: boolean): IPromise<void>; 
    <T>(fn: (...args: any[]) => T, delay?: number, invokeApply?: boolean, ...args: any[]): IPromise<T>; 
    cancel(promise?: IPromise<any>): boolean; 
} 

(見https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/angular/index.d.ts#L603

因此,$timeout(process, 20)返回IPromise<IPromise<IResult>>,拋出一個TS2322錯誤。但你的代碼如何工作?縱觀$超時的實現,我們看到了答案:

... 
deferred.resolve(fn.apply(null, args)); 
... 

$timeout創建一個新的推遲並解決它像deferred.resolve(fn.apply(null, args));,作爲一個承諾鏈工作時FN返回一個承諾。

所以,這裏的問題是$超時簽名! $超時簽名應該是:

interface ITimeoutService { 
    (delay?: number, invokeApply?: boolean): IPromise<void>; 
    <T>(fn: (...args: any[]) => T | IPromise<T>, delay?: number, invokeApply?: boolean, ...args: any[]): IPromise<T>; 
    cancel(promise?: IPromise<any>): boolean; 
} 

可以看到一個說明性的測試用例here

+0

它在這裏解決了https://github.com/DefinitelyTyped/DefinitelyTyped/pull/15364。 –