enum AllowedFruits {
Apple = 'APPLE',
Banana = 'BANANA',
Pear = 'PEAR'
}
const allowedFruits: AllowedFruits[] = [
AllowedFruits.Apple, AllowedFruits.Banana, AllowedFruits.Pear
]
我想要實作的是限制陣列具有特定列舉的每個欄位。我希望allowedFruits通過添加或洗掉AllowedFruits.
有沒有辦法實作它?
如果有任何文章或檔案可以參考,請告訴我。
uj5u.com熱心網友回復:
選項1
我們可以通過創建一個包含所有可能組合的型別來解決這個問題AllowedFruits。
type AllCombinations<T extends string> = [T] extends [never]
? []
: {
[K in T]: [K, ...AllCombinations<Exclude<T, K>>]
}[T]
type AllFruitCombinations = AllCombinations<AllowedFruits>
如果列舉中有很多元素,這可能會導致性能下降,因為需要先計算每個組合。
讓我們看看這是否有效:
/* Error */
const t1: AllFruitCombinations = []
const t2: AllFruitCombinations = [AllowedFruits.Apple]
const t3: AllFruitCombinations = [AllowedFruits.Apple, AllowedFruits.Banana]
const t4: AllFruitCombinations = [AllowedFruits.Apple, AllowedFruits.Banana, AllowedFruits.Pear, AllowedFruits.Pear]
/* OK */
const t5: AllFruitCombinations = [AllowedFruits.Apple, AllowedFruits.Banana, AllowedFruits.Pear]
操場
選項 2
也可以通過傳遞allowedFruits給具有泛型型別的函式來解決這個問題。
我們可以創建一個通用輔助型別ExhaustiveFruits來檢查陣列中是否存在所有列舉值。
type ExhaustiveFruits<
O extends AllowedFruits[],
T extends AllowedFruits[] = O,
P extends string = `${AllowedFruits}`
> = [P] extends [never]
? O
: T extends [`${infer L}`]
? [P] extends [L]
? O
: never
: T extends [`${infer L}`, ...infer R]
? R extends AllowedFruits[]
? ExhaustiveFruits<O, R, Exclude<P, L>>
: never
: never
的邏輯ExhaustiveFruits非常簡單:它是一種遞回型別,我們從所有列舉值 as和asP的元組的聯合開始。AllowedFruitsT
對于 的每個元素T,使用string推斷元素的值'${infer L}'。之后,該值從與 的P聯合中洗掉Exclude<P, L>。
每次迭代都會檢查是否P為空 with[P] extends [never]或最后一個元素是否是 with 的最后一個T元素。如果是這種情況,則可以回傳原始元組。如果為空但仍在其聯合中,則回傳。P[P] extends [L]OTPAllowedFruitsnever
該型別可以在這樣的泛型函式中使用createAllowedFruitsArray:
function createAllowedFruitsArray<
T extends AllowedFruits[]
>(arr: [...ExhaustiveFruits<T>]) : T {
return arr
}
一些檢查以查看這是否有效:
createAllowedFruitsArray(
[] // Error
)
createAllowedFruitsArray(
[AllowedFruits.Apple] // Error
)
createAllowedFruitsArray(
[AllowedFruits.Apple, AllowedFruits.Banana] // Error
)
createAllowedFruitsArray(
[AllowedFruits.Apple, AllowedFruits.Banana, AllowedFruits.Pear] // OK
)
現在也可以多次使用相同的列舉值,只要全部使用。
createAllowedFruitsArray(
[AllowedFruits.Apple,
AllowedFruits.Banana,
AllowedFruits.Pear,
AllowedFruits.Pear] // Also ok, even though Pear is twice in the array
)
但稍作修改,我們也可以改變這一點:
type ExhaustiveFruits<
O extends AllowedFruits[],
T extends AllowedFruits[] = O,
P extends string = `${AllowedFruits}`
> = [P] extends [never]
? O["length"] extends 0
? O
: never
: T extends [`${infer L}`]
? [P] extends [L]
? O
: never
: T extends [`${infer L}`, ...infer R]
? R extends AllowedFruits[]
? [L] extends [P]
? ExhaustiveFruits<O, R, Exclude<P, L>>
: never
: never
: never
操場
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/477936.html
