定义执行共享值的元组列表



我想指定一种在上一个元组中强制执行最后一个值的类型,在下一个元组中匹配第一个值,即:

const contiguousIntervals: ThreeContiguousIntervals = [
  [0, 1],
  [1, 2],
  [2, 3],
];

我已经与以下定义相当接近:

type IntervalMin<TEnd extends number> = [number, TEnd];
type IntervalMax<TStart extends number> = [TStart, number];
type Interval<TStart extends number, TEnd extends number> = [TStart, TEnd];
type ThreeContiguousIntervals<A extends number, B extends number> = [
  NumericIntervalMin<A>,
  NumericInterval<A, B>,
  NumericIntervalMax<B>
];

这有效,但是我必须通过仿制药签名中的值:

// works!
const foo: ThreeContiguousIntervals<2, 3> = [
  [0, 2], [2, 3], [3, 4],
];
// breaks as expected
const bar: ThreeContiguousIntervals<2, 3> = [
  [0, 2], [3, 4], [4, 5],
           ^ throws error: "type '3' is not assignable to type '2'"
];

如何获得打字稿来推断通用签名?

所述问题的答案是使用通用的帮助手函数,并依靠该功能中的类型参数推断,以及各种技巧,以使推断不太宽(例如,,您不希望将bar推断为ThreeContiguousIntervals<2|3, 4>,但可能是(。

,但这也与您的另一个问题相似,因此我不妨给出类似的答案,我们支持任意长度的元素,而不仅仅是长度为三的元素...

您可以使用通用,映射和条件类型来表示所需的形状(数字对的元组,其中每对的第二个元素与下一对的第一个元素是相同的类型(作为对数组类型的约束。这是一种方法:

// prepend a value to a tuple.  Cons<1, [2,3]> is [1,2,3]
type Cons<H, T extends any[]> = ((h: H, ...t: T) => any) extends
    ((...l: infer L) => any) ? L : never;
// verify that T is an array of numeric pairs where the last element of
// each pair is the same as the first element of the next pair
type VerifyContig<T> = T extends Array<any> ?
    { [K in keyof T]: [
        K extends '0' ? number :
        Cons<null, T> extends Record<K, [any, infer N]> ? N : never
        , number
    ] } : never;
// helper function to validate that values match the desired shape
const asContig = <N extends number, T extends [N, N][] | [[N, N]]>(
    contig: T & VerifyContig<T>
): T => contig;
asContig([]); // okay
asContig([[1, 2]]); // okay
asContig([[1, 2], [2, 3]]); // okay
asContig([[1, 2], [3, 4]]); // error!
//                 ~ <-- 3 is not assignable to 2
asContig([[1, 2], [2, 3], [3, 5], [5, 8], [8, 13]]); // okay
asContig([[1, 2], [2, 3], [3, 5], [5, 7], [8, 13]]); // error!
//            8 is not assignable to 7 --> ~

看起来不错。希望有帮助;祝你好运!

最新更新