TypeScript -在封装函数时键入rest参数和返回值



我想创建一个函数,它可以包装任意函数,但参数和结果都保持相同的类型。例如,这将包装一个函数-但是类型将变成any:

// Note that the returned wrappedFn takes the same arguments as fn, and returns
// a value of the same type as the one returned by fn.
function myWrapper(fn: (...args: any[]) => any): (...args: any[]) => any {
return function wrappedFn(...args: any[]) {
// ...some arbitrary code goes here
return fn(...args);
};
}
function repeatString(str: string, times: number): string {
return Array(times + 1).join(str);
}
// TS is aware that wrappedRepeatString is a function, but it infers that
// it takes any parameters, rather than a string and a number.
const wrappedRepeatString = myWrapper(repeatString);
// The result of this call is "foofoofoo" (a string), but TS sees it as "any".
const repeatedString = wrappedRepeatString("foo", 3);
// Since repeatedString is of type "any", this compiles, even though
// it'd crash as there's no "toFixed" method on strings.
repeatedString.toFixed();

我可以输入myWrapper来接受一个函数,它接受一个字符串和一个数字作为参数,并返回一个数字-但是如果我想将它与具有不同参数或返回类型的函数一起使用,我需要编写另一个。理想情况下,我可以编写一个包装器,TS可以推断出wrappedFn(返回函数)的参数和返回值与fn的参数和返回值相同。

请注意,仅仅将其余参数输入为数组类型(例如...args: string[])是行不通的,因为参数也可能是不同的类型。

您可以使用一个泛型变量来描述函数fn,并要求组合函数具有相同的签名。

将函数作为泛型,利用内置的实用程序类型ReturnType<T>Parameters<T>:

function myWrapper<F extends (...args: any[]) => any>(fn: F) {
return function wrappedFn(...args: Parameters<F>): ReturnType<F> {
return fn(...args);
};
}

请注意,虽然组合函数具有与F相同的参数和返回值,但它不能完全赋值给F,因为javascript中的函数是对象,因此F类型可能包含一些组合函数不具有的任意额外属性。

使用ArgsReturn类型作为两个独立的泛型:

function myWrapper<Args extends any[], Return>(fn: (...args: Args) => Return) {
return function wrappedFn(...args: Args): Return {
return fn(...args);
};
}

这两个都给出了repeatedString.toFixed()所需的错误,因为repeatedString的类型现在是string而不是any

最新更新