Как ввести составную функцию с расширенными аргументами в Typescript?

#typescript #typescript-typings

#typescript #typescript-typings

Вопрос:

Насколько я знаю, типы операторов расширения — это массивы. В этом случае fn(...args) возвращается следующая ошибка :

«Невозможно вызвать выражение, у типа которого отсутствует сигнатура вызова. Тип ‘never’ не имеет совместимых сигнатур вызовов. «

Я перепробовал несколько вариантов, но не смог найти решение.

 const callAll = (...fns: []) => (...args: []) => fns.forEach(fn => fn amp;amp; fn(...args));  

Ответ №1:

[] на самом деле это пустой кортеж, и, как таковой, элемент этого кортежа имеет тип never (то есть то, что никогда не может существовать в отношении typescript). Если вы хотите, чтобы массив элементов, которые вы не хотите проверять any[] , был бы способом написать это.

 const callAll = (...fns: any[]) => (...args: any[]) => fns.forEach(fn => fn amp;amp; fn(...args))
  

Хотя это передаст компилятору, это не очень безопасно для типов, мы можем вызывать callAll с любыми аргументами, и typescript не будет жаловаться ( callAll(1,2,3) нормально с точки зрения компилятора)

Первым улучшением было бы сообщить typescript, что передаваемый массив fn должен быть массивом функций:

 const callAll = (...fns: Array<(...a: any[])=> any>) => (...args: any[]) => fns.forEach(fn => fn amp;amp; fn(...args));

const composed = callAll(a => console.log("a "   a), b => console.log("b "   b))
composed("arg");
  

Я использовал Array<T> синтаксис вместо T[] двух, представляющих один и тот же тип, но поскольку T это функция signature ( (...a: any[])=> any ), этот синтаксис легче читать. Сигнатура функции позволит использовать любую функцию в массиве, не связывая их каким-либо образом.

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

Мы можем сделать еще лучше, проверив, что типы параметров совпадают, и типы аргументов также совпадают. Для этого нам нужно будет добавить параметры универсального типа в нашу функцию. P будет представлять типы параметров. Это позволит нам перенаправить типы параметров в возвращаемую функцию, а также обеспечить, чтобы все функции должны иметь одинаковые типы параметров:

 const callAll = <P extends any[]>(...fns: Array<(...a: P)=> void>) => (...args: P) => fns.forEach(fn => fn amp;amp; fn(...args));

const composed = callAll(
    (a: string) => console.log("a "   a), // only first one must specify param types
    b => console.log("b "   b)
) // b is inferred as string
composed("arg");
composed(1); //error must be strings

const composedBad = callAll(
    (a: string) => console.log("a "   a), 
    (b: number) => console.log("b "   b) // error parametr types don't match
)