Typescript 展平嵌套元组类型并保留顺序

Typescript 展平嵌套元组类型并保留顺序,typescript,typescript-typings,typescript-generics,Typescript,Typescript Typings,Typescript Generics,我正在努力实现这样的目标: type ConcatX<T extends readonly (readonly any[])[]> = [ ...T[0], ...T[1], ...T[2], ...T[3], ...T[4], ...T[5], ...T[6], ...T[7], ...T[8], ...T[9], ...T[10], ...T[11], ...T[12], ...T[13], ...T[14], ...T[15], ...T[16]

我正在努力实现这样的目标:

type ConcatX<T extends readonly (readonly any[])[]> = [
    ...T[0], ...T[1], ...T[2], ...T[3], ...T[4],
    ...T[5], ...T[6], ...T[7], ...T[8], ...T[9],
    ...T[10], ...T[11], ...T[12], ...T[13], ...T[14],
    ...T[15], ...T[16], ...T[17], ...T[18], ...T[19]
];
type Flatten<T extends readonly any[]> =
    ConcatX<[...{ [K in keyof T]: T[K] extends any[] ? T[K] : [T[K]] }, ...[][]]>

type InputTuple = [A, B, [C, D], [A, B, D], [A, B, C, D, B], A];
type FlattenedTuple = Flatten<InputTuple>;
// type FlattenedTuple = [A, B, C, D, A, B, D, A, B, C, D, B, A]
type=object;
type TypeTuple=只读类型[];
函数元组(…元组:T):R{
//展平元组并以正确的顺序返回
//示例:扁平元组(A,B,[C,D],[A])=>[A,B,C,D,A]
}
其中,
flattenTuples
函数将展平所提供参数中的每个元组,类型
flatte
实现将执行相同操作并返回元组,例如“
as const
”数组并保留参数元组的顺序。我只需要1级扁平化

再次举例(A、B等都是不同的类构造函数):

const flat=flattenTuples(A,B,[C,D],[A]);
//这将使变量平面的类型:
//[A,B,C,D,A]
我尝试了一个类似的答案,但他的扁平型解决方案不起作用。通过上面的示例,它为TS4.0生成类型
[A,B,C | D,A]

更新:

TS4.0将引入固定数量元组
a
B
C
的串联,这与使用
[…a,…B,…C]
一样简单。这意味着
flatte
可以实现如下功能:

type ConcatX<T extends readonly (readonly any[])[]> = [
    ...T[0], ...T[1], ...T[2], ...T[3], ...T[4],
    ...T[5], ...T[6], ...T[7], ...T[8], ...T[9],
    ...T[10], ...T[11], ...T[12], ...T[13], ...T[14],
    ...T[15], ...T[16], ...T[17], ...T[18], ...T[19]
];
type Flatten<T extends readonly any[]> =
    ConcatX<[...{ [K in keyof T]: T[K] extends any[] ? T[K] : [T[K]] }, ...[][]]>

type InputTuple = [A, B, [C, D], [A, B, D], [A, B, C, D, B], A];
type FlattenedTuple = Flatten<InputTuple>;
// type FlattenedTuple = [A, B, C, D, A, B, D, A, B, C, D, B, A]
前三行由一个小JS脚本生成,以生成一组表示数字加减操作的固定元组,并获得给定长度的“空白”元组。所以
Add[3][4]
应该是
7
Sub[7][3]
应该是
4
Tup[3]
应该是
[0,0,0]

从那里我定义了
Tail
,它取一个元组,如
[1,2,3,4]
,并去掉第一个元素来生成
[2,3,4]
,以及
Concat
,它取两个元组并将它们连接起来(如
Concat
应该是
[1,2,3,4]
)。这里的
Concat
的定义纯粹是迭代的,所以它还不违法

然后我制作了
Tuplize
,它只是确保tuple
T
的每个元素本身就是一个数组。所以你的
[A,B,[C,D],[A]
将变成
[A],[B],[C,D],[A]
。这将消除展平时出现的奇怪边缘条件

最后,我编写了非法递归的
Flatten
。我试着在其中加入一些递归限制;它只适用于长度不超过7米的情况。如果您试图通过将
7
更改为
25
来增加该值,则可能会从编译器中获得错误。无论如何,这里的基本方法是对
Tuplize
执行一种
reduce()
操作:只需将
Concat
Tuplize的第一个元素放到
Tuplized
尾部的
展平版本上

让我们看一个例子:

type InputTuple = [A, B, [C, D], [A, B, D], [A, B, C, D, B], A];
type FlattenedTuple = Flatten<InputTuple>;
// type FlattenedTuple = [A, B, C, D, A, B, D, A, B, C, D, B, A]
type inputUple=[A,B[C,D],[A,B,D],[A,B,C,D,B],A];
类型FlattedTuple=展平;
//类型FlattedTuple=[A,B,C,D,A,B,D,A,B,C,D,B,A]
看起来不错

这里有各种各样的警告;它只展平一层深(这是你要求的)。它可能不会在工会中传播。对于
readonly
或可选元组或数组,它可能不会按照您想要的方式运行。对于太长或任意长度的元组,它肯定不能正常工作。如果月球是满月或者木星与火星对齐,它可能不会正常工作

上面代码的要点不是让您将其放入生产系统中。请不要那样做。这只是为了对类型系统有一些乐趣,并表明这是一个开放的问题


好吧,希望这会有帮助;祝你好运

TypeScript提供了我们目前的解决方案,这将使jcalz@的解决方案更加出色:

type Tuple = readonly any[]
type Tail<T extends Tuple> = T extends [any, ...infer U] ? U : []
type Concat<T extends Tuple, U extends Tuple> = [...T, ...U];
type Tuplize<T> = { [K in keyof T]: T[K] extends unknown[] ? T[K] : [T[K]] }

type Flatten<T extends Tuple> =
  Tuplize<T> extends infer U ?
    U extends Tuple ?
      { 0: [], 1: Concat<U[0], Flatten<Tail<U>>>}[U extends [] ? 0 : 1]
      : never
    : never;
type Tuple=readonly any[]
类型Tail=T扩展[任何,…推断U]?U:[]
Concat类型=[…T,…U];
类型Tuplize={[K in keyof T]:T[K]扩展未知[]?T[K]:[T[K]}
类型展平=
Tuplize扩展推断U?
U扩展元组?
{0:[],1:Concat}[U扩展[]?0:1]
:从不
:从不;
尽管这是基于一个实验性的提议,没有像jcalz的答案那样的递归控制,而且,出于明显的原因,不应该在生产中使用,直到4.0真正发布并且可变类型的语法最终确定


做梦很有趣,对吧?感谢您对github问题的深入回答和链接!这正是我所需要的,可惜没有一种方法比这更简单。这可能有助于让这个问题变得更清晰,正如您所提到的。我们继续前进,为像我这样的人提供了一个答案,他们想知道,在一个变量类型和递归条件类型的官方支持的世界中,您令人敬畏的解决方案会是什么样子。