我有python的背景,而且我喜歡玩函式式語言,我正在學習typescript,所以我想有一個zip()函式,其作業方式有點像Python的。我看到 typescript 已經獲得了生成器和變數泛型,所以我認為這應該是可能的。我有一些東西非常接近我想要的東西,但還不完全。我確信我要么是做了什么明顯的事情,要么是我即將了解 typescript 型別系統的深層運作。
我想要的是一個函式,它接收一個數量可變的陣列,并從這些陣列中產生一個元素的元組,直到最短的陣列被用完。我寫了一個生成器,它可以做到這一點,但我在正確打字方面遇到了困難。
function* zip<T extends any[]> (. .args: T) {.
for (let i = 0; i < Math.min( ...args. map((e) => { return e.length }); i) {
yield args.map((e) => { return e[i]; }) as T。
}
如果我去掉as T,那么這個函式就能作業,但是我失去了所有的型別資訊,如果不這樣做,那么我得到了一個回傳型別[...T[]],但是我想要[...T]。
例如,zip([1, 2, 3], ['a', 'b', 'c']),應該有一個[number, string]的回傳型別,但它有[number[], string[]
uj5u.com熱心網友回復:
你可能想要像這樣的型別:
function* zip<T extends any[][] > (. .args: T) {.
for (let i = 0; i < Math.min( ...args. map((e) => { return e.length }); i) {
yield args.map((e) => { return e[i]; }) as
{ [I in keyof T]: T[I] extends Array<infer E> ? E : never };
}
}
注意,你希望args是一個陣列的陣列,對嗎? args的每個元素本身應該有一個length屬性,并且有通過數字索引訪問的元素。 所以T extends any[][]將為你做到這一點(你甚至可能想放松它,以便它也接受readonly陣列,但我不會去討論這個問題。
你不希望為生成器產生的每個元素回傳T,因為那是一個陣列的陣列。 如果你不對回傳進行注釋,那么你就會得到編譯器認為map()產生的任何東西,這必然會比你所尋找的東西更不精確(請參閱將元組型別的值映射到不同的元組型別的值,而無需進行轉換以了解更多資訊)。 你必須斷定型別,但它不是T。
相反,對于T的索引中的每個數字索引I,你想從該索引處獲取陣列型別T[I],并回傳該陣列的元素型別。 我們可以使用映射型別來表示這種轉換,因為圖元上的映射型別產生圖元。 這就是{ [I in keyof T]: T[I]擴展為陣列<推斷出E>? E : never }這樣做。
好吧,我們來測驗一下:
for(const z of zip([1, 2, 3], ['a'/span>, 'b'/span>, 'c'/span>]) {
console.log(z[0] 。 toFixed(2) ", " z[1].toUpperCase()
// "1.00, A" "2.00, B" "3.00, C"
}
看起來不錯;編譯器看到z是[數字,字串],并讓你相應地處理z的每個元素。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/318606.html
標籤:
