打字稿保持对象上的类型信息映射

时间:2020-10-08 14:29:58

标签: typescript typescript-generics

我有一个包含函数的对象,必须包装这些函数才能使用它们的返回值,而无需更改其签名并保留类型信息。

// 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

在包装函数时是否可以保留类型信息(函数列表及其参数)?

2 个答案:

答案 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。返回值wrappedasserted,属于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

我想看起来像你想要的。

Playground link to code

答案 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,以获得有关打字的一些解释。