我希望确保AgeDivisions和EventStyles都至少有一个真值.

以下是我喜欢的类型:

type AgeDivisions = {
  youth: boolean;
  middleSchool: boolean;
  highSchool: boolean;
  college: boolean;
  open: boolean;
};

type EventStyles = {
  folkstyle: boolean;
  freestyle: boolean;
  grecoRoman: boolean;
  jello: boolean;
  noGiJits: boolean;
  giJits: boolean;
  judo: boolean;
  beach: boolean;
};

type EventInfo = {
  name: string;
  venueName: string;
  address: string;
  date: string;
  subTitle: string;
  country: string;
  eventType: EventType;
  hasGirlsOnlyDivision: boolean;
  link: string;
  ageDivisions: AgeDivisions;
  eventStyles: EventStyles;
  latitude: string;
  longitude: string;
  description: string;
};

我想实现这一点的方法是创建一个泛型类型,我将把AgeDivisions和EventStyles传递给它.然而,只为他们每一个人制作一种新型号可能会更容易

推荐答案

您可以创建自己的实用程序类型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

Typescript相关问答推荐

为什么ESLint抱怨通用对象类型?

参数类型undefined不能分配给参数类型字符串|未定义

如何使类型只能有来自另一个类型的键,但键可以有一个新值,新键应该抛出一个错误

在TypeScript中,除了映射类型之外还使用的`in`二进制运算符?

使Typescribe强制所有对象具有相同的 struct ,从两个选项

如何按不能保证的功能过滤按键?

我可以为情态车使用棱角形的路由守卫吗?

打字类型保护递归判断

如何在处理数组时缩小几个派生类实例之间的类型范围?

推断从其他类型派生的类型

防止重复使用 Select 器重新渲染

基于泛型的条件接口键

如何在Reaction 18、Reaction-Rout6中的导航栏中获取路由参数

TypeScrip:如何缩小具有联合类型属性的对象

如何在Nextjs路由处理程序中指定响应正文的类型

带有';的类型脚本嵌套对象可选属性错误满足';

typescript如何从映射类型推断

递归JSON类型脚本不接受 node 值中的变量

我可以使用对象属性的名称作为对象中的字符串值吗?

从接口推断模板参数?