Я пытаюсь понять, как обернуть определенные функции, чтобы я мог выполнять дополнительную работу, сохраняя их подписи. Вот желаемый эффект:
Программист определяет интерфейс:
const actions = {
first: (id: number) => {/*...*/},
second: (name: string) => {/*...*/}
}
let actionsInterface = wrap(actions)
export actionsInterface
actionsInterface
должен (т. Е. Это цель) иметь следующий интерфейс:
{
first: (id: number) => void,
second: (name: string) => void
}
Он в основном предоставляет тот же самый интерфейс (то есть тот же список функций, с теми же параметрами, не считая возвращаемого типа), что и был определен вначале, но выполняется дополнительная работа, которая была введена wrap()
.
Моя текущая реализация выглядит примерно так:
type VarFn = (...args: any) => any
function wrap<T, K extends keyof T>
(funcList: Record<K, T[K] extends VarFn ? T[K] : never>) {
// this maps a specific function to a function that does something extra
function wrapOne<T extends (...args: any)=>any>(fn: T) {
return (...args: Parameters<typeof fn>) => {
someMagicThingyExtra(fn(args))
}
}
// we iterate through the list and map each function to the one that's doing something extra
type FuncMap = Record<K, (...args: Parameters<T[K] extends VarFn ? T[K] : never>)=>void>
let map: FuncMap
for (var Key in funcList) {
let func = funcList[Key]
map[Key] = wrapOne(func)
}
return map
}
Однако на wrap(actions)
появляется следующая ошибка:
Argument of type '{ first: (id: number) => void; second: (name: string) => void; }' is not assignable to parameter of type 'Record<"first" | "second", never>'.
Types of property 'first' are incompatible.
Type '(id: number) => void' is not assignable to type 'never'.
Так что по какой-то причине (id: number) => void
не совпало с (...args: any) => any
, поэтому было получено never
.
Поэтому я попробовал немного другое:
function wrap2<T, K extends keyof T, U extends VarFn>
(funcList: Record<K, U>) {
function wrapOne<T extends (...args: any)=>any>(fn: T) {
return (...args: Parameters<typeof fn>) => {
someMagicThingyExtra(fn(args))
}
}
type FuncMap = Record<K, (...args: Parameters<U>)=>void>
let map: FuncMap
for (var Key in funcList) {
let func = funcList[Key]
map[Key] = wrapOne(func)
}
return map
}
Ошибок нет, но мой возвращаемый тип wrap2(actions)
:
{
first: (...args: any) => void
second: (...args: any) => void
}
... и я потерял типы параметров, что сводит на нет всю цель попытки обернуть функциональность, но сохранить сигнатуры (то есть типы параметров).
Любая помощь или руководство приветствуются. Спасибо!
РЕДАКТИРОВАТЬ:
Драгомир предоставил ответ, который полностью сохраняет подпись (как типы параметров, так и типы возвращаемых значений). В моем варианте использования также потребовалось изменить тип возвращаемого значения на void
, и вот как я этого добился:
function wrap<T extends Record<keyof T, (...args: any)=>any>>(funcList: T) {
// this maps a specific function to a function that does something extra
function wrapOne<T extends (...args: any) => any>(fn: T) {
return ((...args: Parameters<typeof fn>): void => {
someMagicThingyExtra(fn(args))
})
}
// we iterate through the list and map each function to the one that's doing something extra
type WrapMap = {
[K in keyof T]: (...args: Parameters<T[K]>)=>void
}
let map: WrapMap
for (var Key in map) {
map[Key] = wrapOne(funcList[Key])
}
return map
}