Typescript - 包装函数同时保留签名

问题描述 投票:0回答:3

我正在尝试找出如何包装定义的函数,以便我可以在保留其签名的同时做额外的工作。这是想要的效果:

程序员定义接口:

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)

...并且我丢失了参数类型,这违背了尝试包装功能但保留签名(即参数类型)的整个目的。

欢迎任何帮助或指导。谢谢!

编辑:

Dragomir 提供的答案完全保留了签名(参数类型和返回类型)。我的用例还需要将返回类型更改为

{ first: (...args: any) => void second: (...args: any) => void }

,这就是我实现它的方法:


void

	
typescript type-inference typescript-generics
3个回答
3
投票
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 }

应该有一个约束,即它的所有成员都是

T
类型,您可以轻松地使用
VarFn
来实现。由于返回的类型与输入类型
T extends Record<keyof T, VarFn>
完全相同,因此可以是
map
类型。

T

游乐场链接


1
投票

type VarFn = (...args: any) => any function wrap<T extends Record<keyof T, VarFn>>(funcList: T) { // this maps a specific function to a function that does something extra function wrapOne<T extends (...args: any) => any>(fn: T): T { return ((...args: Parameters<typeof fn>) => { return someMagicThingyExtra(fn(args)) }) as T } // we iterate through the list and map each function to the one that's doing something extra let map = {} as T for (var Key in funcList) { let func = funcList[Key] map[Key] = wrapOne(func) } return map } const actions = { first: (id: number) => {/*...*/ }, second: (name: string) => {/*...*/ } } let actionsInterface = wrap(actions)



0
投票

const newFunction = ((one, two) => { const result = oldFunction(one, two) // ... return result }) as typeof oldFunction

	
© www.soinside.com 2019 - 2024. All rights reserved.