我有一个包含函数的对象,必须包装这些函数才能使用它们的返回值,而无需更改其签名并保留类型信息。
// a object containing functions
const functions = { foo, bar, baz }
// example wrapper
const doSomething: (result: any) => void;
// wrapper function for each function
function wrapper<P extends any[]>(fn: (...params: P) => any) {
return (...params: P) => doSomething(fn(...params));
}
// the wrap function, which needs type information
function wrap(functions) {
const wrapped = {};
for (const key in functions) {
wrapped[key] = wrapper(functions[key]);
}
return wrapped;
}
const wrapped = wrap(functions);
// get type information for wrapped and its functions here
在包装函数时是否可以保留类型信息(函数列表及其参数)?
答案 0 :(得分:4)
TypeScript不会为您推断出此高阶类型的操作;您必须在某些地方进行注释和声明。检查wrapper
显示的类型
/* function wrapper<P extends any[]>(fn: (...params: P) => any): (...params: P) => void */
因此它将返回一个函数,该函数的参数与输入函数相同,但返回void
。在这种情况下,我会像这样写wrap()
:
function wrap<T extends Record<keyof T, (...args: any) => any>>(functions: T) {
const wrapped = {} as { [K in keyof T]: (...p: Parameters<T[K]>) => void };
for (const key in functions) {
wrapped[key] = wrapper(functions[key]);
}
return wrapped;
}
functions
参数的通用类型为T
,它是属性为函数的对象类型的constrained。返回值wrapped
为asserted,属于mapped type,其属性名称与T
相同,其值函数类型与{的对应属性相同{1}},但返回类型已更改为T
。这使用Parameters
utility type来表示输出函数采用与输入函数相同的参数。
当我为Stack Overflow编写代码时,我希望有完整的示例,所以这是我正在使用的定义:
void
然后,当我致电const functions = {
foo: (x: string) => x.length,
bar: (x: number) => x.toFixed(2),
baz: (x: boolean, y: boolean) => x && y;
}
const doSomething = (result: any) => { console.log(result) };
时,我们会得到以下行为:
wrap()
如果我尝试做错了事,编译器会抱怨:
const wrapped = wrap(functions);
wrapped.foo("hey"); // 3
wrapped.bar(Math.PI); // 3.14
wrapped.baz(true, false); // false
我想看起来像你想要的。
答案 1 :(得分:0)
借助jcalz answer,我制作了一个更通用的函数对象映射器。
它将给定功能包装对象中的每个功能,而无需更改对象类型签名。
function mapFunctionsObj<T extends Record<keyof T, (...p: any[]) => any>>(
fn: <X>(result: X) => X,
functions: T
) {
const mapped = {} as any;
for (const key in functions) {
mapped[key] = (...params) => fn(functions[key](...params));
}
return mapped as { [K in keyof T]: (...p: Parameters<T[K]>) => ReturnType<T[K]> };
}
请阅读original answer,以获得有关打字的一些解释。