从元组类型中删除所有可选项



假设我想将具有可选项(如[1, 2, 3?, 4?](的元组转换为仅包含所需项的数组->[1, 2]

我想出的如下所示,它从不涉及所有可选项目,我被困在这里。

type OnlyReq <L extends any []> = {
[K in keyof L]-?: L [K] extends Required <L> [K]  ? L [K] : never
}
type Found = OnlyReq <[1, 2, 3?, 4?]> // [1, 2, never, never]

操场

我在这里的方法是编写一个递归条件类型(实际上是尾递归,所以它适用于TS4.5+中相当长的元组(,它遍历元组,直到发现它的其余部分都是可选的。

请注意,元组类型中的可选元素后面不能跟必需元素;也就是说,像[1, 2?, 3]这样的东西是不可能的。因此,如果元组有任何必需的元素,则第一个元素必须是必需的。

这里有一个实现:

type OnlyReq<T extends any[], U extends any[] = []> = Partial<T> extends T ? U :
T extends [infer F, ...infer R] ? OnlyReq<R, [...U, F]> : U

我们在类型参数U(以空元组[]开始(中累积结果,因此一旦我们决定停止迭代,我们就会返回U

检查Partial<T> extends T使用Partial<T>实用程序类型来生成输入元组的全可选版本。一般来说,T extends Partial<T>是真的,但Partial<T> extends T不是,除非T已经和Partial<T>一样。。。换句话说,Partial<T> extends T当且仅当T都是可选的。

如果元组T都是可选的,那么我们返回U。此外,如果T为空,则返回U(如果T不能被分割为第一元素F和休息元组R,则会发生这种情况(。如果T有第一个元素F,那么我们知道它是必需的(否则T将是可选的(,并且我们可以将它推到U元组的末尾,以便递归调用元组R的其余部分。


让我们看看它是否有效:

type Found = OnlyReq<[1, 2, 3?, 4?]>
// type Found = [1, 2]

看起来不错。

还要注意,元组类型中的rest元素也被认为是"剩余元素";可选的";在同一测试中,因此它们也应该被剥离:

type StripRest = OnlyReq<[string, boolean?, ...number[]]> 
// type StripRest = [string]

事实上,非元组数组类型(Foo[](等效于仅由rest元素([...Foo[]](组成的元组,因此将被转换为空元组,这可能是也可能不是您想要的:

type Hmm = OnlyReq<number[]>
// type Hmm = []

我正在考虑";前导";或";中间的";元组类型中的rest元素不在这里的范围内,因为它们会做一些奇怪的事情,而你没有问过它们(我希望它不会出现,因为操作这样的类型很烦人(:

type What = OnlyReq<[...string[], number]>
// type What = []
type AlsoWhat = OnlyReq<[string, ...boolean[], number]>
//type AlsoWhat = [string]

游乐场链接到代码

最新更新