Ответ на ваш вопрос, как указано, состоит в том, чтобы использовать универсальную вспомогательную функцию и полагаться на вывод аргументов типа в этой функции вместе с различными приемами, чтобы вывод не был слишком широким (например, вы не хочу, чтобы ваш 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 --> ~
выглядит хорошо. Надеюсь, это поможет; удачи!