问题描述
假设我想要将具有[1, 2, 3?, 4?]
等可选项的元组转换为仅包含必需项的数组->;[1, 2]
我想出来的如下所示,它变成了Never All Option Items,我被困在这里。
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]
推荐答案
我在这里的方法是编写一个recursive conditional type(实际上是tail recursive,因此它将适用于TS4.5+中相当长的元组),它遍历tuple,直到它发现其余的都是可选的。
请注意,optional elements in tuple types后面不能跟必需的元素;也就是说,像[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
使用the Partial<T>
utility type得到输入元组的全可选版本。一般来说,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 elements in tuple types在同一测试中也被认为是可选的,因此它们也应该被去除:
type StripRest = OnlyReq<[string, boolean?, ...number[]]>
// type StripRest = [string]
实际上,非元组数组类型(Foo[]
)等同于仅由一个rest元素([...Foo[]]
)组成的元组,因此将被转换为空元组,这可能是您想要的,也可能不是:
type Hmm = OnlyReq<number[]>
// type Hmm = []
我认为"leading" or "middle" rest elements in tuple types超出了这里的范围,因为它们会做奇怪的事情,而您没有问到它们(我希望不会出现,因为操作这种类型很烦人):
type What = OnlyReq<[...string[], number]>
// type What = []
type AlsoWhat = OnlyReq<[string, ...boolean[], number]>
//type AlsoWhat = [string]
这篇关于从元组类型中删除所有可选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!