簡體   English   中英

`promise.all` 的類型定義在這種情況下如何運作良好?

[英]How does the type defination of `promise.all` work well in this case?

我在做一道type-challenges的題的時候發現了這個問題。

以下代碼在情況 3 中將失敗:

declare function PromiseAll<A extends readonly unknown[]>(values: A): Promise<{
  -readonly [key in keyof A]: Awaited<A[key]>
}>

// test
const promiseAllTest3 = PromiseAll([1, 2, Promise.resolve(3)]) 
// except Promise<[number, number, number]>, but got Promise<number[]>

但是當我將通用readonly unknown[]更改為(readonly unknown[]) | [] (readonly unknown[]) | []像下面這樣,一切都會好的。

declare function PromiseAll<A extends (readonly unknown[]) | [] /* change here */>(values: A): Promise<{
  -readonly [key in keyof A]: Awaited<A[key]>
}>

// test
const promiseAllTest3 = PromiseAll([1, 2, Promise.resolve(3)]) // Promise<[number, number, number]>

我不明白為什么向通用“A”添加“[]”約束會影響案例 3。我根本無法將它們關聯起來。

另外,正確的實現是我在vscode中找到的lib.es2015.promise.d.ts的標准實現

// lib.es2015.promise.d.ts
/**
 * Creates a Promise that is resolved with an array of results when all of the provided Promises
 * resolve, or rejected when any Promise is rejected.
 * @param values An array of Promises.
 * @returns A new Promise.
 */
all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }>;

我發現這段代碼工作正常。 因為它通過轉換為 Tuple 來保留所有類型及其位置:

declare function PromiseAll<A extends any[]>(values: readonly [...A]): Promise<{
  [key in keyof A]: Awaited<A[key]>
}>

基本上它是窄元組[number, number, number]類型而不是加寬數組number[]因為添加... | [] ... | []到類型,將文字類型[]添加到定義返回類型的上下文中,在本例中為通用A

這是詳細解釋/實現正在發生的事情的 PR: GitHub

並且您的代碼是 PR 中引入的以下更改的完美示例:

為數組文字中的元素推斷的類型是表達式的擴展文字類型,除非該元素具有包含文字類型的上下文類型。

PromiseAll的返回類型在A的上下文中定義。 A又在其定義中使用文字類型。 因此它構成了一個“包含文字類型的上下文類型”,阻止了從元組到數組的類型擴展。

作為傳遞給函數的數組文字的默認推斷行為,TypeScript 團隊選擇推斷數組類型而不是元組類型。

如果將鼠標懸停在函數調用上,您可以在工具提示中看到它:

declare function PromiseAll<A extends readonly unknown[]>(values: A): void

PromiseAll([1, 2, Promise.resolve(3)])
// function PromiseAll<(number | Promise<number>)[]>(...)

A的類型被推斷為數組類型(number | Promise<number>)[]而不是元組類型[number, number, Promise<number>]

這種行為在大多數情況下都可以正常工作,但要正確鍵入Promise.all()函數,我們需要推斷元組類型。 有多種方法可以做到這一點,您在問題中發現了其中兩種。


但是為什么這兩種方法都可以推斷出元組類型呢? 我們可以在#31434中從ahejlsberg得到澄清

我們僅在上下文類型是或包含類似元組的類型時推斷元組類型

這幾乎是最重要的一點。 (readonly unknown[]) | [] (readonly unknown[]) | []起作用是因為約束中的聯合現在包含一個元組類型[] 這足以提示編譯器推斷元組類型。

使用readonly [...A]也可以推斷元組,因為它使用的是4.0中引入的可變元組語法。 有關使用可變元組類型進行推理的詳細說明,請參閱PR/#39094

當數組文字的上下文類型是元組類型時,將為數組文字推斷出元組類型。 類型 [...T],其中 T 是類似數組的類型參數,可以方便地用於指示對元組類型推斷的偏好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM