【问题标题】:In TypeScript, how to define a recursive function that return a promise在 TypeScript 中,如何定义一个返回 Promise 的递归函数
【发布时间】:2017-06-09 21:20:16
【问题描述】:

我们仍然使用 angular 1.5.8,我尝试编写一个函数,将长时间的计算分解为部分。由于可以将 promise 与返回 promise 的函数链接起来,所以我想这样写:

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

这可行,但 TypeScript 编译器会抱怨,因为 Angular $timeout 服务接受一个返回值的函数,而不是一个承诺:

TS2322:类型“IPromise”不可分配给类型“IPromise”。 “IPromise”类型中缺少属性“add”。

有没有办法在这个函数中正确定义类型?

我可以看到两个选择:

  1. 定义进程返回any
  2. 转换返回语句:

return $timeout(process, 20) as any as ng.IPromise&lt;IResult&gt;

有更好的主意吗?

【问题讨论】:

    标签: typescript promise settimeout


    【解决方案1】:

    $timeout 签名是:

    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&lt;IPromise&lt;IResult&gt;&gt;,这会引发 TS2322 错误。但是你的代码是如何工作的?查看 $timeout 实现,我们看到了答案:

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

    $timeout 创建一个新的 deferred 并像 deferred.resolve(fn.apply(null, args)); 一样解析它,当 fn 返回一个 Promise 时,它​​作为一个 Promise 链工作。

    所以,这里的问题是 $timeout 签名! $timeout 签名应该是:

    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

    【讨论】:

    猜你喜欢
    • 2023-03-13
    • 2016-06-23
    • 2022-01-26
    • 2012-09-26
    相关资源
    最近更新 更多