const foo = (a: string, b: string) => {
console.info('foo', a, b);
};
const bar = (a: number, b: number) => {
console.info('bar', a, b);
};
const factory =
<M extends typeof foo | typeof bar>(method: M) =>
(...args: Parameters<M>) => {
method(...args);
};
Я хочу создать фабрику нескольких функций (имеет разные аргументы)
Но TypeScript выдает ошибку ниже сообщения.
A spread argument must either have a tuple type or be passed to a rest parameter.
Возвращает ли Parameters
кортеж типа утилиты?
Это ограничение конструкции, описанное в ms/TS#47615 . Рекомендуемый подход — сделать рефакторинг общим для списка параметров, а не для типа функции, как показано в этой ссылке на игровую площадку. Это полностью решает вопрос? Если да, то я напишу ответ с объяснением; если нет, то что мне не хватает?
@jcalz Это работает идеально! Спасибо :D
TypeScript не очень хорошо понимает общие условные типы ; в частности, он не всегда может просмотреть тип утилиты «Параметры<M>» для универсального типа функции M
и понять, что выходные данные всегда можно расширять. Это считается ограничением дизайна TypeScript, как описано в microsoft/TypeScript#47615.
В соответствии с этой проблемой рекомендуемый подход — сделать функцию универсальной в списке аргументов A
и возвращаемом типе R
типа функции отдельно. Для вашего кода тип возвращаемого значения всегда void
, поэтому мы можем сделать его просто универсальным в A
:
const factory = <A extends Parameters<typeof foo | typeof bar>>(
method: (...args: A) => void) => (...args: A) => {
method(...args);
};
Поскольку известно, что тип A
из args
является типом остальных параметров для method
, вызов разрешен. И хотя для примера это не обязательно важно, A
было ограничено до Parameters<typeof foo | typeof bar>
, чтобы вы не могли передавать случайные функции в:
factory(foo)("a", "b"); // okay
factory(bar)(1, 2); // okay
factory((a: string, b: number) => { }) // error!
Мне кажется, это ошибка TypeScript. Это работает, если вручную сделать функцию
M extends (...args: Parameters<typeof foo | typeof bar>) => (ReturnType<typeof foo | typeof bar>)
.