从元组类型中删除所有可选项目
Remove all optional items from a Tuple type
假设我想将一个包含可选项(如 [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]
我这里的做法是写一个recursive conditional type (actually tail recursive so it will work for quite long tuples in TS4.5+) that walks through the tuple,直到它发现剩下的部分都是可选的。
注意optional elements in tuple types后面不能跟必需的元素;也就是说,像 [1, 2?, 3]
这样的东西是不可能的。因此,如果元组具有 any 个必需元素,则必须特别需要第一个元素。
这是一个实现:
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
中累积结果(它以空元组 []
开始),所以一旦我们决定停止迭代,我们 return 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
是全可选的,那么我们 return U
。此外,如果 T
为空,我们 return U
(如果 T
不能拆分为第一个元素 F
和其余元组 R
).如果 T
有第一个元素 F
,那么我们知道它是必需的(否则 T
将是全可选的),我们可以将它推到 [=16= 的末尾] 元组的其余部分的递归调用 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[]
) 等同于仅由剩余元素 ([...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]
假设我想将一个包含可选项(如 [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]
我这里的做法是写一个recursive conditional type (actually tail recursive so it will work for quite long tuples in TS4.5+) that walks through the tuple,直到它发现剩下的部分都是可选的。
注意optional elements in tuple types后面不能跟必需的元素;也就是说,像 [1, 2?, 3]
这样的东西是不可能的。因此,如果元组具有 any 个必需元素,则必须特别需要第一个元素。
这是一个实现:
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
中累积结果(它以空元组 []
开始),所以一旦我们决定停止迭代,我们 return 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
是全可选的,那么我们 return U
。此外,如果 T
为空,我们 return U
(如果 T
不能拆分为第一个元素 F
和其余元组 R
).如果 T
有第一个元素 F
,那么我们知道它是必需的(否则 T
将是全可选的),我们可以将它推到 [=16= 的末尾] 元组的其余部分的递归调用 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[]
) 等同于仅由剩余元素 ([...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]