Сборник рассказов действия аддон предоставляет удобный способ регистрации вызовов обратного вызова:
renderButton({onClick: action('onClick')});
Вызов action
возвращает функцию, которая регистрирует строку (onClick
) и аргументы, с которыми он вызывается.
Иногда я хочу иметь и action
, и что-то еще:
renderButton({
onClick: (arg1, arg2, arg3) => {
action('onClick')(arg1, arg2, arg3);
// ... my code
}
});
Вызов action
стал более подробным, так как я должен передать все аргументы. Итак, я реализовал функцию both
, позволяющую мне писать:
renderButton({
onClick: both(action('onClick'), (arg1, arg2, arg3) => {
// ... my code
})
});
Это отлично работает, пока я не попытаюсь добавить типы TypeScript. Вот моя реализация:
function both<T extends unknown[], This extends unknown>(
a: (this: This, ...args: T) => void,
b: (this: This, ...args: T) => void,
): (this: This, ...args: T) => void {
return function(this: This, ...args: T) {
a.apply(this, args);
b.apply(this, args);
};
}
Этот тип проверяет и работает во время выполнения, но в зависимости от контекста он либо приводит к нежелательным типам any
, либо к ошибкам типов. Например:
const fnWithCallback = (cb: (a: string, b: number) => void) => {};
fnWithCallback((a, b) => {
a; // type is string
b; // type is number
});
fnWithCallback(
both(action('callback'), (a, b) => {
a; // type is any
b; // type is any
}),
);
fnWithCallback(
both(action('callback'), (a, b) => {
// ~~~~~~~~~~~
// Argument of type '(a: T[0], b: T[1]) => number' is not assignable to
// parameter of type '() => void'.
}),
);
Возможно ли, чтобы both
правильно захватил типы аргументов из контекста обратного вызова? И чтобы избежать типов any
, которые предположительно возникают из объявления action
:
export type HandlerFunction = (...args: any[]) => void;
Вот ссылка на игровую площадку с полным примером.