不确定是否可行,但是我希望能够定义一个将元组转换为[number, string, undefined, number]
到[number, string, number]
(即过滤掉undefined
)的类型。
我想到了这样的事情:
type FilterUndefined<T extends any[]> = {
[i in keyof T]: T[i] extends undefined ? /* nothing? */ : T[i];
}
可悲的是,我很确定没有办法实现这一目标。
答案 0 :(得分:8)
知道了!但是它需要很多递归魔术:
type PrependTuple<A, T extends Array<any>> =
A extends undefined ? T :
(((a: A, ...b: T) => void) extends (...a: infer I) => void ? I : [])
type RemoveFirstFromTuple<T extends any[]> =
T['length'] extends 0 ? undefined :
(((...b: T) => void) extends (a, ...b: infer I) => void ? I : [])
type FirstFromTuple<T extends any[]> =
T['length'] extends 0 ? undefined : T[0]
type NumberToTuple<N extends number, L extends Array<any> = []> = {
true: L;
false: NumberToTuple<N, PrependTuple<1, L>>;
}[L['length'] extends N ? "true" : "false"];
type Decrease<I extends number> = RemoveFirstFromTuple<NumberToTuple<I>>['length']
type H = Decrease<4>
type Iter<N extends number, Items extends any[], L extends Array<any> = []> = {
true: L;
false: Iter<FirstFromTuple<Items> extends undefined ? Decrease<N> : N, RemoveFirstFromTuple<Items>, PrependTuple<FirstFromTuple<Items>, L>>;
}[L["length"] extends N ? "true" : "false"];
type FilterUndefined<T extends any[]> = Iter<T['length'], T>
type I = [number, string, undefined, number];
type R = FilterUndefined<I>
工作原理:
PrependToTuple是一种实用程序,它接受项A
并列出T
,并且在A
未被定义时将其添加到第一位。 PrependToTuple<undefined, []> => []
,PrependToTuple<undefined, [number]> => [number]
RemoveFirstFromTuple
的工作原理与我相当
NumberToTuple
递归检查最终元组的长度是否为N
,如果
不,他在递归调用中加1。创建Decrease
实用程序需要该实用程序。
最重要的z Iter
类似于递归循环,当最终元组的长度为N
(Input
的大小)时,它的返回值为Output
,但是{{1 }}在尝试添加PrependToTuple
时并没有增加长度,因此当undefined
时我们必须减少N。
答案 1 :(得分:5)
元组上的过滤操作现在可以officially:
type FilterUndefined<T extends any[]> = T extends [] ? [] :
T extends [infer H, ...infer R] ?
H extends undefined ? FilterUndefined<R> : [H, ...FilterUndefined<R>] : T
让我们做一些测试来检查它是否按预期工作:
type T1 = FilterUndefined<[number, string, undefined, number]>
// [number, string, number]
type T2 = FilterUndefined<[1, undefined, 2]> // [1, 2]
type T3 = FilterUndefined<[undefined, 2]> // [2]
type T4 = FilterUndefined<[2, undefined]> // [2]
type T5 = FilterUndefined<[undefined, undefined, 2]> // [2]
type T6 = FilterUndefined<[undefined]> // []
type T7 = FilterUndefined<[]> // []
答案 2 :(得分:3)
补充答案:
ford04's answer 中方法的扩展允许我们创建一个“拼接器”实用程序类型,它可以删除任意索引处的值(以防有人在寻找类型安全 {{1} }).
这涉及创建一个实用程序类型,该类型将从给定的元组和索引生成带有 splice
的元组:
undefined
那么这只是组合 type UndefIndex<T extends any[], I extends number> = {
[ P in keyof T ] : P extends Exclude<keyof T, keyof any[]> ? P extends `${I}` ? undefined : T[P] : T[P]
}
和 UndefIndex
类型的问题:
FilterUndefined
答案 3 :(得分:-4)
我了解您要做什么 - 您要删除所有未定义的元素,而不管索引如何。
您的问题出现在“typescript omit tuple element”中的第一个结果。我在找那个是因为我想在使用Parameters<SomeFunction>
时省略第一个参数,所以我会让自己从表面上理解你的问题,所以如何转:
[number, string, undefined, number]
到 [number, string, number]
答案是:
type InputTuple = [number, string, undefined, number];
//notice there's NO InputTuple[2]!!
type OutputTuple = [InputTuple[0], InputTuple[1], InputTuple[3]]