2017-01-24 41 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。 –