#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
)