Wzorce
Jak przyjąć obiekt opcji, w którym każde pole jest opcjonalne, ale pusty obiekt jest niedozwolony?
Zbuduj po jednym wariancie na klucz, w którym ten klucz jest wymagany, a reszta opcjonalna, i połącz je unią. Każdy pojedynczy podany klucz spełnia co najmniej jeden wariant.
Przepis
type AtLeastOne<T> = { [K in keyof T]: Required<Pick<T, K>> & Partial<Omit<T, K>> }[keyof T] type Filters = { name?: string age?: number } type ValidFilters = AtLeastOne<Filters>
Build to kompiluje i sprawdza każdy wynik poniżej.
Jak to działa
- 01
Required<Pick<T, K>> & Partial<Omit<T, K>>
Jeden wariant: ten klucz wymagany, cała reszta opcjonalna. `Required` ma znaczenie, bo źródłowe właściwości już były opcjonalne.
- 02
}[keyof T]Zindeksuj całą tablicę wszystkimi kluczami naraz, zapadając warianty w unię. Ta sama sztuczka, którą archiwum zamienia tablicę odnośników w odpowiedź.
Co dostajesz
{ name: 'a' } extends ValidFilters ? true : false→true{} extends ValidFilters ? true : false→falsePusty obiekt nie spełnia żadnego wariantu, bo każdy wariant wymaga dokładnie jednego klucza.
{ name: 'a'; age: 1 } extends ValidFilters ? true : false→true
Gdzie to zawodzi
Unia rośnie wraz z liczbą kluczy, a komunikaty błędów razem z nią — dziesięciokluczowy typ opcji daje dziesięcioskładnikową unię i diagnostykę, której nikt nie przeczyta. Zostaw to dla małych zestawów opcji.
Wniosek
Zmapuj na warianty, potem zindeksuj przez `keyof`, by je złączyć. Ten dwukrok to ogólny kształt dla „co najmniej jedno z tych”.