typescript 如何要求类型不为空

2ic8powd  于 2023-05-19  发布在  TypeScript
关注(0)|答案(1)|浏览(235)

假设我有一个所有属性都是可选的类型:

type T = {
  x?: number;
  y?: string;
  z?: number;
  ...
}

有没有一种方法可以构造一个类型,允许所有类型T的值,但至少需要一个属性?例如:

let a: NotEmpty<T> = { z: 1 }; // ok
a = {}; // error

当然,这样做的一种方法是将至少具有一个所需属性的所有组合合并,但是当属性的数量很大时,这会变得有点尴尬。有没有更一般的方法?

o2gm4chl

o2gm4chl1#

您所谈论的“至少具有一个必需属性的所有组合”的联合并不太难编写,特别是因为您可以编写NotEmpty<T>实用程序类型来自动计算它。并且该类型的每个属性键只有一个联合成员,因此它可以很好地扩展属性的数量(它不是阶乘或组合爆炸或任何东西)。
这里有一种写法:

type NotEmpty<T> = T &
  { [K in keyof T]-?: { [P in K]-?: T[K] } }[keyof T];

所以一个NotEmpty<T>T与某物相交,所以我们知道,至少NotEmpty<T>T的一个子类型。我们用来交叉的东西,

{ [K in keyof T]-?: { [P in K]-?: T[K] } }[keyof T]

是一个 * 分布式对象类型 *(如在microsoft/TypeScript#47109中创造的),一个mapped type,我们立即将index与其所有键一起得到一个并集。在上面,我们得到keyof T中每个K{[P in K]-?: T[K]}的并集。
{[P in K]-?: T[K]}类型等价于Required<Pick<T, K>>(参见RequiredPick实用程序类型):一个明确具有来自TK属性的对象。
所以整件事就是:NotEmpty<T>是一个T,它也被称为具有T中的属性中的 * 一些 * 定义的属性。
让我们在你的例子中测试一下:

type NotEmptyT = NotEmpty<T>
/* type NotEmptyT = T & ({ x: number; } | { y: string; } | { z: number; }) */

看起来不错,让我们确保它的行为符合预期:

let a: NotEmpty<T>;
a = { z: 1 }; // ok
a = {}; // error

看起来也不错!
Playground链接到代码

相关问题