我想到了一个“可行”的东西,但有点疯狂:
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 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)
这里有一个带有一些测试用例的实时演示。
我实际上不建议在典型代码库中依赖它(使用起来很麻烦,错误消息也很糟糕)。我主要是为了看看类型系统能够被拉伸到多远而一直在努力。
如果有人有关于如何使其更加不稳定的建议,我非常乐意听取!
[A, B][]
,一个元组的数组呢? - jonrsharpe