Ввод функции с произвольным числом различных аргументов - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть функция с именем pipeline() В настоящее время она имеет тип

function pipeline(firstFn: Function, ...fns: Function[]) {
  let previousFn = firstFn()
  for (const func of fns) {
    previousFn = func(previousFn)
  }
  return previousFn
}

Если я использую ее для конвейерной передачи некоторых функций

const add = (x: number) => (y: number) => x+y
const result = pipeline(
   () => 4,
   add(2),
   add(4)
)
// 10

Однако с этим решением нетпроверка типов, что типы аргументов функций соответствуют типам возврата предыдущих функций, а тип возвращаемого значения прост any.

Я понимаю, что это не может быть полностью напечатано (например, Promise.all([])имеет максимум 10 обещаний, с которыми он может справиться до того, как сдастся), но я бы хотел иметь проверку типов при вызовах хотя бы нескольких аргументов.

1 Ответ

0 голосов
/ 22 февраля 2019

Простое решение

В случае, когда тип возвращаемого значения каждой функции в конвейере одинаков, это может быть достигнуто с помощью обобщений довольно легко:

function pipeline<T>(firstFn: () => T, ...fns: ((arg: T) => T)[]): T {
    let previousFn = firstFn()
    for (const func of fns) {
      previousFn = func(previousFn)
    }

    return previousFn
}

Более полныйрешение

Первое, что нам нужно понять, это как Promise.all к нему относится?

Из исходного текста lib.es2015.promise.d.ts :

all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;

all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;

all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;

...

all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>;

Они написали перегрузку для функции для каждого числа элементов, начиная с 10 и вплоть до общего универсального элемента.

Вот почему строгая типизация Promise.all для возвращаемого массива помогает более чем 10 элементам с различным типом ввода.

Если вы хотите повторить это поведение, вам нужно будет приложить те же усилия.Вот как это будет выглядеть для трех параметров:

interface PipelineInterface {
    <T0, T1, T2>(a0: () => T0, a1: (a: T0) => T1, a2: (a: T1) => T2): T2;
    <T0, T1>(a0: () => T0, a1: (a: T0) => T1): T1;
    <T>(firstFn: () => T, ...fns: ((arg: T) => T)[]): T;
}

const pipeline: PipelineInterface = function (firstFn, ...fns) {
    let previousFn = firstFn()
    for (const func of fns) {
      previousFn = func(previousFn)
    }

    return previousFn
}

const result = pipeline(
    () => 4,
    (a) => a + 'Hello'
)
// result has type string

const result2 = pipeline(
    () => 4,
    (a: string) => a + 'Hello'
)
// Argument of type '(a: string) => string' is not assignable to parameter of type '(a: number) => string'.
...