У меня есть функция с определенными типами аргументов. Аргументы: key, который является ключом указанного интерфейса IBook, и value, который должен иметь тип, соответствующий этому конкретному ключу в интерфейсе. т.е. если key === 'id', то единственным допустимым типом для value должен быть number.
Проблема возникает, когда я хочу создать другую функцию, чтобы просто передавать аргументы из события onChange в первое. Чтобы избежать повторного объявления аргументов функции, я использовал Parameters generic, но, похоже, он ведет себя неправильно. Проверьте использование ниже.
interface IBook {
id: number;
title: string;
isPromoted?: boolean;
}
export const editBook = <K extends keyof Required<IBook>>(
key: K,
value: Required<IBook>[K],
) => ({
type: 'EDIT_BOOK',
payload: { key, value },
});
const onChange = (...args: Parameters<typeof editBook>) => {
dispatch(editBook(...args));
};
editBook('id', 'some string'); // string not accepted here, shows error
onChange('id', 'some string'); // no error here
editBook('id', true); // boolean not accepted here, shows error
onChange('id', true); // no error here
Если я использую исходную функцию editBook, то value набирается правильно — только та, которая соответствует типу key. Если я использую другой, отображается ошибка. Однако, если я использую функцию-оболочку onChange, то любой тип, существующий в IBook, принимается в качестве аргумента value.
Как я могу это исправить?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Когда вы используете Parameters, вы не захватываете параметры типа исходной функции, typescript просто использует ограничение, где он находит любую ссылку на параметр типа, поэтому подпись onChange на самом деле будет просто:
(key: keyof IBook, value: Required<IBook>[keyof IBook]) => void
что получится:
(key: "id" | "title" | "isPromoted", value: string | number | boolean) => void
разрешение недействительных вызовов.
К сожалению, нет явного способа захватить параметры типа и передать их новой функции. Начиная с версии 3.4, существует неявный способ сделать это, используя функцию конвейера как описано здесь.
function pipe<A extends any[], B, C>(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C {
return (...args: A) => bc(ab(...args));
}
function dispatch<T extends { type: string }>(action: T): void {
}
const onChange = pipe(editBook, dispatch); // generic type parameter preserved
editBook('id', 'some string'); // string not accepted here, shows error
onChange('id', 'some string'); // error now
editBook('id', true); // boolean not accepted here, shows error
onChange('id', true); // error now
Спасибо за объяснение! Как жаль, что
Parametersтак не работает.