繁体   English   中英

如何在 TypeScript 中定义具有交替类型的数组?

[英]How to define array with alternating types in TypeScript?

我想定义一个数组类型,它允许根据 position 使用不同的类型,但是以在某些数据结构中发现的重复、交替的方式。

例子:

[A, B, A, B, ...]
[A, B, C, A, B, C, ...]

这可能吗?

我知道我可以为 arrays 定义它,上面有固定数量的元素(没有省略号),并且

(A | B)[]

另一方面,将允许任何元素为 A 或 B 类型。

我试过这些:

[(A, B)...]
[...[A, B]]
[(A, B)*]

我想出了一些“有效”的东西,但这有点疯狂:

type Alternating<T extends readonly any[], A, B> =
  T extends readonly [] ? T
  : T extends readonly [A] ? T
  : T extends readonly [A, B, ...infer T2]
    ? T2 extends Alternating<T2, A, B> ? T : never
  : never

由于递归条件类型,这需要 TypeScript 4.1+。


幼稚的用法需要将值复制为T参数的文字类型,这并不理想:

const x: Alternating<[1, 'a', 2], number, string> = [1, 'a', 2]

这似乎比仅仅写出[number, string, number]作为类型更糟糕。 然而,在虚拟 function 的帮助下,可以避免重复:

function mustAlternate<T extends readonly any[], A, B>(
  _: Alternating<T, A, B>
): void {}

const x = [1, 'a', 2] as const
mustAlternate<typeof x, number, string>(x)

这是一个带有一些测试用例的现场演示


我实际上并不建议在典型的代码库中依赖它(使用起来很尴尬,而且错误消息很糟糕)。 我大多只是通过它来查看类型系统可以延伸多远。

如果有人对如何使它不那么不稳定有任何建议,我全神贯注!

替代方法:

type MAXIMUM_ALLOWED_BOUNDARY = 50

type Mapped<
    Tuple extends Array<unknown>,
    Result extends Array<unknown> = [],
    Count extends ReadonlyArray<number> = []
    > =
    (Count['length'] extends MAXIMUM_ALLOWED_BOUNDARY
        ? Result
        : (Tuple extends []
            ? []
            : (Result extends []
                ? Mapped<Tuple, Tuple, [...Count, 1]>
                : Mapped<Tuple, Result | [...Result, ...Tuple], [...Count, 1]>)
        )
    )



type Result = Mapped<[string, number, number[]]>

// 3 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48
type Test = Result['length']

/**
 * Ok
 */
const test1: Result = ['a', 42, [1]]
const test2: Result = ['a', 42, [1], 'b', 43, [2]]

/**
 * Fail
 */
const test3:Result = ['a'] // error

const fn = <T, U>(tuple: Mapped<[T, U]>) => tuple

fn([42, 'hello']) // ok
fn([42, 'hello','sdf']) // expected error

操场

Mapped - 丑陋的名字,但工作:D。 创建元组的所有允许状态的联合。 每个允许的元组 state 的长度可以除以 3: length%3===0 // true 你可以定义任何你想要的元组,有 4 个值,5 个等等......

每次迭代我都会将Count数组增加 1。这就是我知道何时停止递归迭代的方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM