Typescript - 具有不同 return 值的动态承诺数组

Typescript - dynamic array of promises with different return values

任何人都可以帮我解决这段代码有什么问题吗? 我找不到合适的类型来放入底部的 Promise.all 调用。 它也尝试了 Promise.all<Services[], PullRequests[]>(ops)PullRequests[] 不能是可选的...

function wait<Twait>(time: number, response: Twait): Promise<Twait> {
    return new Promise(resolve => setTimeout(() => resolve(response), time))
}

interface Service {
    name: string;
    id: number;
}

async function getServices(): Promise<Service[]>  {
    const response = await wait(400, { "id": 200 });
    return [{ name: "service", id: response.id }]
}


interface PullRequest {
    prType: string;
    githubId: number;
}

async function getPrs(): Promise<PullRequest[]>  {
    const response = await wait(400, { "githubId": 200 });
    return [{ prType: "foo", githubId: response.githubId }]
}


async function main(): Promise<void> {

    const ops: [ PromiseLike<Service[]>, PromiseLike<PullRequest[]>? ] = [getServices()]

    if (Math.random() > 0.5) { // <== this is random on purpose.
        ops.push(getPrs())
    }
    
    
    const [ services, prs ] = await Promise.all(ops) // This throws a ts compile error (attached below)
    console.log("services:")
    console.log(services)
    console.log("prs:")
    console.log(prs)    
}

No overload matches this call. The last overload gave the following error.
 Argument of type '[PromiseLike<Service[]>, (PromiseLike<PullRequest[]> | undefined)?]' is not assignable to parameter of type 'Iterable<Service[] | PromiseLike<Service[] | undefined> | undefined>'. 
The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types. 
Type 'IteratorResult<PromiseLike<Service[]> | PromiseLike<PullRequest[]> | undefined, any>' is not assignable to type 'IteratorResult<Service[] | PromiseLike<Service[] | undefined> | undefined, any>'. 
Type 'IteratorYieldResult<PromiseLike<Service[]> | PromiseLike<PullRequest[]> | undefined>' is not assignable to type 'IteratorResult<Service[] | PromiseLike<Service[] | undefined> | undefined, any>'. 
Type 'IteratorYieldResult<PromiseLike<Service[]> | PromiseLike<PullRequest[]> | undefined>' is not assignable to type 'IteratorYieldResult<Service[] | PromiseLike<Service[] | undefined> | undefined>'. 
Type 'PromiseLike<Service[]> | PromiseLike<PullRequest[]> | undefined' is not assignable to type 'Service[] | PromiseLike<Service[] | undefined> | undefined'. 
Type 'PromiseLike<PullRequest[]>' is not assignable to type 'Service[] | PromiseLike<Service[] | undefined> | undefined'. 
Type 'PromiseLike<PullRequest[]>' is not assignable to type 'PromiseLike<Service[] | undefined>'. 
Type 'PullRequest[]' is not assignable to type 'Service[]'. 
Type 'PullRequest' is missing the following properties from type 'Service': name, id

根据 microsoft/TypeScript#28427. Currently the library hardcodes a bunch of specific tuple types which do not include optional elements. There has been some effort taken to fix this, but apparently PromiseLike types and how they interact with await are complicated enough that none of the pull requests fixing this have been accepted yet. A comment in microsoft/TypeScript#39788 的说法,这似乎是 TS 库定义中的一个已知问题,解释说切换它可能会破坏依赖于当前定义的现有现实世界代码。

除非上游解决这个问题,否则您可以使用 declaration merging to add your own signature for Promise.all() that just maps 对 passed-in array-or-tuple:

的元素展开承诺
interface PromiseConstructor {
  all<T extends readonly any[]>(
    values: { [K in keyof T]: T[K] | PromiseLike<T[K]> }
  ): Promise<T>;
}

您可以测试它是否按照您的要求运行:

const promiseAllOps = Promise.all(ops); // no error now  
// const promiseAllOps: Promise<[Service[], (PullRequest[] | undefined)?]>
const awaitPromiseAllOps = await promiseAllOps;
// const awaitPromiseAllOps: [Service[], (PullRequest[] | undefined)?]
const [services, prs] = awaitPromiseAllOps;
services; // Service[]
prs; // PullRequest[] | undefined

Playground link