Динамичная типизация параметров функции

Описание

Есть некий класс MachineState<T> и T это тип, который он "принимает". Я создаю функцию, которая "поддает" сразу несколько данных, нескольким MachineState-ам:

await context.runFunctionsParallel(sign(5), [
    [this.#stateBettingOnSport, { id: 3 }], /// [MachineState<A>, A]
    [this.#stateBettingOnCasino, { code: "cb12" }], /// [MachineState<B>, B]
]);

Собственно, создаю эту функцию:

async runFunctionsParallel<T extends readonly [MachineState<object>, object][]>(signature: SignatureGenerator, values: {
    -readonly [K in keyof T]:
    T[K] extends [MachineState<infer P>, infer V]
    ? P extends V
    ? V extends P
    ? [MachineState<P>, P]
    : never
    : never
    : never;
}): Promise<unknown[]> {
    ...
}

Проблема

Функция не выдает ошибок, но и не работает. Я не получаю типовые подсказки и проверки.

Вопрос

Где моя ошибка?


Дополнение 1

Пример описания функции, которое работает, без массива:

async runFunction<T extends {}>(signature: SignatureFunction, state: MachineState<T>, data: T): Promise<unknown> {
    ...
}

Ответы (1 шт):

Автор решения: Alexandroppolus

Вкратце, что неправильно прямо сейчас:

  1. При вызове функции TS не знает, за что зацепиться для определения T. В типе параметра values этот самый T должен быть "напрямую": values: T & {...}. Но такой способ может допускать лишние ключи, и не факт что будет нормально подсказывать существующие.

  2. Если сделать по способу из п.1, T выводится как массив. А надо кортеж, иначе может пропускать несоответствия типов.

Дополнение к ответу

Поэкспериментировал в плейграунде, вышло так.

П.1 решается за счет трюка с тернарником: values: T extends unknown ? Pairs<T> : T. Здесь, с одной стороны, формально T может быть типом для values, и TS выставляет в него тип переданного объекта. С другой стороны, по факту условие всегда истинно, и мы идем в Pairs, где на основе T формируем желаемый тип, по которому и делается проверка для переданного значения. Круг замкнулся, в общем.

П.2 разруливается странным ограничением для T, с участием кортежа: T extends [Item, ...Item[]] | Item[]. Без этого T выводился как массив, даже вышеупомянутый const не помогал. Тут без комментариев.

→ Ссылка