Определите список кортежей, которые применяют общие значения - PullRequest
0 голосов
/ 11 мая 2019

Я хочу указать тип, который заставляет последнее значение в предыдущем кортеже соответствовать первому значению в следующем кортеже, то есть:

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>
];

Это работает, но я должен передать значения в сигнатуре generics:

// 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'"
];

Как мне заставить TypeScript выводить общую подпись?

1 Ответ

1 голос
/ 11 мая 2019

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

выглядит хорошо. Надеюсь, это поможет; удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...