我想在 TypeScript 中創建一個聯合型別,它可以使用陣列作為判別式,但如果陣列的任何元素滿足某些條件,而不是陣列中的所有元素,則具有特定的型別匹配。
例如,這應該可行,因為任何有狗的家庭都可以指定品種:
const homes: Household[] = [{
humans: 3,
pets: ['cat', 'dog'],
dogBreeds: ['mutt'],
}];
但這不應該,因為沒有狗的家庭永遠不應該指定狗的品種:
const homes: Household[] = [{
humans: 3,
pets: ['cat'],
dogBreeds: ['mutt'],
}];
我的想法是我應該像這樣定義我的型別:
type PetType = 'dog' | 'cat' | 'hamster';
interface NoDogHousehold {
humans: number;
pets: Exclude<PetType, 'dog'>[];
dogBreeds?: never;
}
interface DogHousehold {
humans: number;
pets: 'dog'[];
dogBreeds: string[];
}
type Household = DogHousehold | NoDogHousehold;
The problem with this is that DogHousehold will now only apply if all elements in pets are 'dog'. So it would work for ['dog'] or ['dog', 'dog'], but not ['cat', 'dog']. Using a tuple type could work, but I don't see any way I can create such a type without a predictable number/order of elements. The closest tuple type I could think of was ['dog', PetType?, PetType?], but this is awkward and only works if dog comes first.
Is there some way I can make TypeScript enforce type correctness like this? Or is this kind of type discrimination not possible? Any suggestions on a more reasonable approach are appreciated!
uj5u.com熱心網友回復:
為此,我們需要一種方法dogBreeds來了解它是什么pets。為此,我們需要一個泛型:
type Household<Pets extends ReadonlyArray<string>> = {
當然pets是型別Pets:
pets: Pets;
}
然后我們說,如果Pets包含"dog",則添加dogBreeds:
& (Pets extends [] ? {} : "dog" extends Pets[number] ? { dogBreeds: string[]; } : {})
但首先我們檢查是否Pets為空。否則,如果它是空的,dogBreeds無論如何都會出現。
我們將此檢查的結果與 的基相交{ pets: Pets; }。
然后我們也可以用貓來做:
& (Pets extends [] ? {} : "cat" extends Pets[number] ? { catBreeds: string[]; } : {})
但是,我們不能像這樣使用這種型別:
const house: Household = { ... };
TypeScript 要求我們在這里使用泛型,但是我們需要復制代碼,這并不理想。
為了解決這個問題,我們需要一個包裝函式來為我們進行推斷:
function household<Pets extends ReadonlyArray<string>>(household: Household<Pets>): Household<Pets> {
return household;
}
現在我們可以使用它了:
const house = household({ ... });
操場
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/442544.html
