具有泛型类型的Typescript包装函数

具有泛型类型的Typescript包装函数,typescript,typescript-generics,Typescript,Typescript Generics,如何在不更改Typescript中的泛型类型的情况下包装函数 function x() { console.log('Original Function'); } function wrapper<T extends Function>(func: T): T { // Typescript compiler error: // Type '() => void' is not assignable to type 'T'. return () => {

如何在不更改Typescript中的泛型类型的情况下包装函数

function x() {
  console.log('Original Function');
}

function wrapper<T extends Function>(func: T): T {
  // Typescript compiler error:
  // Type '() => void' is not assignable to type 'T'.
  return () => {
    console.log('Wrapped Function');
    func.call(null);
  }
}

const xWrapped = wrapper(x);
xWrapped(); // logged 'Wrapped Function' & 'Original Function'
函数x(){
console.log(“原始函数”);
}
函数包装器(func:T):T{
//Typescript编译器错误:
//类型“()=>void”不可分配给类型“T”。
return()=>{
log('Wrapped Function');
函数调用(空);
}
}
常数xWrapped=wrapper(x);
xWrapped();//记录的“包装函数”和“原始函数”

包装器函数应接收函数并返回与签名类型完全相同的函数

Typescript无法知道传递的函数接受了多少个参数或返回了什么,而您的函数隐式地假设它接受了0个参数(除此之外)并返回void

目前还没有一种很好的方法将函数签名保存在typescript中。但是,针对更高版本的新建议可能会解决此问题:

现在,您可以制作一个类似这样的通用包装器

function wrapper<T extends (...args:any[])=>any>(func: T): T {
  return <T>((...args:any[]) => {
        console.log('Wrapped Function');
        return func(...args);
    });
}
函数包装器any>(func:T):T{
return((…args:any[])=>{
log('Wrapped Function');
返回函数(…参数);
});
}
对于可变类型的建议,这个函数可以这样写

function wrapper<...TArgs,TRet>(func:(...args:...TARGS)=>TRet) {
    return (...args:...TARGS) => {
        console.log("Wrapped function");
        return func(...args);
    }
}
函数包装器(func:(…参数:…目标)=>TRet){
返回(…参数:…目标)=>{
log(“包装函数”);
返回函数(…参数);
}
}
注意这里的主要区别是没有强制转换,上面的解决方案必须告诉编译器返回变量与输入变量的类型相同。但是,对于变量类型,参数本身可以进行一般类型化。
(注意变量类型当前不在typescript中,当包含do时,上述代码完全可能有语法错误)

这里有一个替代方法,它保留参数并返回内部函数的类型,而不依赖于变量类型

function x(message: string): void {
    console.log(`inner ${message}`);
}

export function wrapper<Args extends any[], Return>(
    operation: (...operationParameters: Args) => Return, 
    ...parameters: Args
): Return {
    console.log(`outer `);

    return operation(...parameters);
}

x("abc");
wrapper(x, "xyz");

// output:
//
// inner abc
// outer
// inner xyz
函数x(消息:字符串):无效{
log(`internal${message}`);
}
导出函数包装器(
操作:(…操作参数:Args)=>返回,
…参数:Args
):返回{
console.log(`outer`);
返回操作(…参数);
}
x(“abc”);
包装(x,“xyz”);
//输出:
//
//内abc
//外
//内xyz
当使用
x
调用
wrapper
时,TS编译器将其类型推断为
函数包装(操作:(operationParameters\u 0:string)=>void,parameters\u 0:string):void


如果您尝试调用
包装器(x,123)
,它会失败,因为类型安全性很好:
类型为“123”的参数不能分配给类型为“string”的参数。

此建议如何解决此问题?@PRAISER您可以为函数参数指定泛型类型列表。该示例显示了完全通用的curry/partial应用程序函数的使用。这意味着像fn.bind和fn.apply这样的东西在将来可能是类型安全的。