您可以创建自己的实用程序类型AtLeastOneTrue<K>
,它接受union个键类型K
并生成一个联合,其中每个成员都有-boolean
个属性,但只有一个成员只能是true
.这将允许一个以上为true
,但禁止它们全部为false
.这里有一种方法可以让你做到这一点:
type AtLeastOneTrue<K extends string> =
{ [P in K]: { [Q in K]: Q extends P ? true : boolean } }[K]
这基本上就是distributive object type(在ms/TS#47109中被创造出来).如果您有一个类似键的类型K
的联合,其计算结果为K1 | K2 | K3
,并且您希望将其转换为F<K1> | F<K2> | F<K3>
,则可以使用{[P in K]: F<P>}[K]
形式的分布式对象类型.这将创建一个新的对象类型,并立即对其进行索引,从而生成其属性的联合.因此,输出不是对象(好吧,除非F<P>
生成对象).
不管怎样,我们的内心操作F<P>
是{[Q in K]: Q extends P ? true : boolean}
.conditional type Q extends P ? true : boolean
负责 for each 键生成boolean
个属性,但我们关注的键除外,它将是true
个属性.
让我们看看它对AgeDivisions
做了什么:
type AgeDivisions = AtLeastOneTrue<
"youth" | "middleSchool" | "highSchool" | "college" | "open"
>;
/* type AgeDivisions = {
youth: true;
middleSchool: boolean;
highSchool: boolean;
college: boolean;
open: boolean;
} | {
youth: boolean;
middleSchool: true;
highSchool: boolean;
college: boolean;
open: boolean;
} | { ⋯
highSchool: true;
⋯ } | { ⋯
college: true;
⋯ } | {
youth: boolean;
middleSchool: boolean;
highSchool: boolean;
college: boolean;
open: true;
} */
并确保其行为符合预期:
let a: AgeDivisions;
a = { college: false, highSchool: false, middleSchool: true,
open: false, youth: false }; // okay
a = { college: true, highSchool: false, middleSchool: false,
open: true, youth: false }; // okay
a = { college: false, highSchool: false, middleSchool: false,
open: false, youth: false }; // error
看上go 不错!所以你可以像这样定义EventStyles
type EventStyles = AtLeastOneTrue<
"folkstyle" | "freestyle" | "grecoRoman" | "jello" |
"noGiJits" | "giJits" | "judo" | "beach"
>;
Playground link to code个