代码之家  ›  专栏  ›  技术社区  ›  Normunds Kalnberzins

在运行时确定回调函数的签名

  •  0
  • Normunds Kalnberzins  · 技术社区  · 8 年前

    我希望将不同的回调函数作为参数传递,并使用适当的参数调用它们。

    下面是一个高度简化的示例,说明它应该如何工作。除了 process instanceof ITwo 没有理智,我也找不到任何表达方式。

        interface IOne { (j: string): number; }
        interface ITwo { (j: number): number; }
        function dualArg(i: string, process: IOne | ITwo): number {
            // something like this
            if (process instanceof ITwo) {
                // call with numeric arg
                return process(i);
            } else {
                // conver to number
                return process(+i);
            }
        }
        function inc(i: number): number {
            return ++i;
        }
        function idem(text: string): number {
            return +text;
        }
        it('determine function signature', () => {
            expect(dualArg('1', inc)).toBe(2);
            expect(dualArg('1', idem)).toBe(1);
        })
    

    对于普通参数 instanceof 对于TypeScript来说,将其视为特定类型的对象就足够了,但是函数似乎没有任何相似之处。

    如果我使用某种硬编码条件,例如 process.prototype.constructor.name === 'idem' 我收到Typescript错误消息: Cannot invoke an expression whose type lacks a call signature. Type 'IOne | ITwo' has no compatible call signatures.

    这里我当然可以定义 process: any 禁用任何类型脚本检查,代码将编译并运行,但我的目标是能够仅通过签名来区分函数(而不依赖于名称或其他标志等其他约定)。

    2 回复  |  直到 8 年前
        1
  •  2
  •   Titian Cernicova-Dragomir    8 年前

    问题是,在运行时,所有类型信息都会丢失。因此,您不能在运行时直接推断函数的类型(除了它是函数这一事实之外)。

    您可以做的是创建一个函数类型,该函数类型还具有一个确定类型的属性。并使用函数来构建函数:

    enum Type { One, Two}
    interface IOne { (j: string): number; type: Type.One }
    interface ITwo { (j: number): number; type: Type.Two}
    function dualArg(i: string, process: IOne | ITwo): number {
        if (process.type === Type.One) {
            // Type guard above, process is of type IOne
            return process(i);
        } else {
            // Type guard above, process is of type ITwo
            return process(+i);
        }
    }
    function inc(i: number): number {
        return ++i;
    }
    function idem(text: string): number {
        return +text;
    }
    
    function oneFunction(fn: (j: string)=> number) : IOne{
        return Object.assign(fn, { type: Type.One as Type.One });
    }
    
    function twoFunction(fn: (j: number)=> number) : ITwo{
        return Object.assign(fn, { type: Type.Two as Type.Two });
    }
    
    dualArg("", twoFunction(inc));
    dualArg("", oneFunction(idem));
    

    对于您的简单示例,这可能有点过头了(您可以定义 dualArg )但是,如果函数的创建和使用相去甚远,并且有更多的代码可以在两者之间重用,那么这种方法可能是有意义的。

        2
  •  0
  •   gilamran    8 年前

    TypeScript仅为开发时间。您不能期望它在运行时执行某些操作。 TypeScript能够使用您的运行时假设“理解”事情(如 instanceof ).

    看起来您的两个函数应该有一个带有两个重载的实现,而不是在 dualArg (调用)函数。处理内部的参数类型 dualArg公司 意味着您必须在任何要调用这些函数的地方执行相同的操作。

    那么,如何实现一个包装器函数来进行参数测试(在运行时),TypeScript将检测并保护您。

    推荐文章