繁体   English   中英

在Typescript中将类方法作为参数传递

[英]Passing class method as parameter in Typescript

我正在寻找将类方法传递给函数的可能性,然后该函数可以在该类的实例上执行该函数。 类似于那个伪代码:(注意这是一个抽象的例子)

class Foo {
    public somefunc() {
        // do some
    }
    public anyfunc() {
        // do any
    }
}

function bar(obj: Foo ,func: "Foo.method") {  // "that's what im looking for"
    obj.func();
}

bar(new Foo(), Foo.somefunc);  // do some
bar(new Foo(), Foo.anyfunc);  // do any

有没有可能做到这一点?

我知道我可以做这样的事情:

class Foo {
    static somefunc(fooObj: Foo) {
        // do some
    }
    static anyfunc(fooObj: Foo) {
        // do any
    }
}

interface func {
    (fooObj: Foo);
}

function bar(obj: Foo, fn: func) {
    fn(obj);
}

bar(new Foo(), Foo.somefunc);  // do some
bar(new Foo(), Foo.anyfunc);  // do any

但这涉及我不想要的静态函数。

这不会在编译时检查函数是否来自Foo ,但会检查其余部分:

class Foo {
    public somefunc() {
        // do some
    }
    public anyfunc() {
        // do any
    }
}

function bar(obj: Foo ,func: () => void) {
    func.call(obj);
}

bar(new Foo(), Foo.prototype.somefunc);  // do some
bar(new Foo(), Foo.prototype.anyfunc);  // do any

打字稿 2+ 解决方案

TL;DR : TypeScript Playground , Repo with a demo

优点:

  1. 编译时检查。
  2. 传递实例的方法时不会让您丢失this上下文。
  3. 不要失去性能:不必将类的方法声明为实例方法(例如public somefunc = () => { return this.prop; } ) - 了解更多
  4. 不要弄乱类的原型。
  5. 一致的签名模式:将回调作为第一个参数传递,将thisArg作为第二个参数传递(例如Array.prototype.map() )。

考虑以下代码:

class Foo {
    private result: number = 42;

    public func(this: Foo): number {
        return this.result;
    }
}

function action(): void {
    console.log("Hello world!");
}

function bar(callbackFn: (this: void) => any, thisArg?: undefined): any;
function bar<T>(callbackFn: (this: T) => any, thisArg: T): any;
function bar<T, TResult>(callbackFn: (this: T) => TResult, thisArg: T): TResult {
    return callbackFn.call(thisArg);
}

const foo = new Foo();

bar(action); // success
bar(foo.func); // ERROR: forgot to pass `thisArg`
bar(foo.func, foo); // success

将注意力转向Foo#func的签名:

public func(this: Foo): number

它指出这个函数应该在类的实例的上下文中调用。 这是解决方案的第一部分,不会让您丢失this上下文。

第二部分是bar函数重载:

function bar(callbackFn: (this: void) => any, thisArg?: undefined): any;
function bar<T>(callbackFn: (this: T) => any, thisArg: T): any;
function bar<T, TResult>(callbackFn: (this: T) => TResult, thisArg: T): TResult

这将使您可以传递通用函数以及实例方法。

您可以在 TypeScript 手册中了解有关这些主题的更多信息:

  1. 回调中的this参数
  2. 函数重载
  3. 泛型

我假设您正在寻找某种方式让 TypeScript 编译器强制执行给定的函数存在于 Foo 上? 不幸的是,我认为没有办法做到这一点。 也许另一位 TypeScript 大师可以进来并更具体地回答这个问题,但我很确定这是你能得到的最接近的:

class Foo {
    constructor(private name:string) { }

    public somefunc() {
        console.log("someFunc called on", this.name);
    }
    public anyfunc() {
        console.log("anyFunc called on", this.name);
    }
}

function bar(obj: Foo, func: string) {
    if (obj[func] && obj[func] instanceof Function) {
        obj[func]();
    } else {
        throw new Error("Function '" + func + "' is not a valid function");
    }
}

bar(new Foo("foo1"), "somefunc");  // output: 'somefunc called on foo1'
bar(new Foo("foo2"), "anyfunc");  // output: 'anyfunc called on foo1'
bar(new Foo("foo3"), "badFunction");  // throws: Error: Function 'badFunction' is not a valid function

是的,像这样声明函数:

myfunction(action: () => void){
   action();
}

从打字稿中这样称呼它:

myfunction(() => alert("hello"));

或者从javascript:

myfunction(function() { alert("hello"); });

你也可以通过方法:

myfunction(this.someMethod);

对我来说; 根据问题的陈述,我可以这样做:

class Foo {
    public constructor() {
        this.welcome = this.welcome.bind(this)
    }

    public welcome(msg: string): void {
        console.log(`hello ${msg}`)
    }
}

function bar(msg: string, fn: void): void {
    fn(msg)
}

const foo = new Foo()
bar('world', foo.welcome) // 'hello world'

此外,我应该指出,我受到了 这个清晰解释的启发。

希望能帮助到你 !

您可以使用粗箭头函数。 他们不应该失去“这个”

class Foo {
    public somefunc = () => {
        // do some
    }
    public anyfunc = () => {
        // do any
    }
}

Javascript 会允许这样做,但不确定这是否是您想要的?

class Foo {
 public someFunc(name:string){
  return "Hello, " + name;
 }

function bar(funcName: string) {
    return eval(funcName);
}

console.log(bar("new Foo().someFunc('erik')"));

在我看来,您应该在这种情况下使用外观设计模式。

当您创建一个复杂的库、工具或系统时,由许多函数和/或类组成; 它变得难以理解和依赖。 所以你应该实现一个提供简单统一接口的类。

class Foo{

      public somefunc() {
        console.log("some")
      }

      public anyfunc() {
        console.log("any")
      }


    };


    class FuncFacade {

      getFunc(obj: any, func_name: string) {
        switch (func_name) {
          case obj.somefunc.name: {
            return obj.somefunc;
          }

          case obj.anyfunc.name: {
            return obj.anyfunc;
          }
          default: {
            throw new Error("No such func!");
          }

        }
      }
    }

    let ff = new FuncFacade();

    function bar(obj: Foo, func_name: string) {
      ff.getFunc(obj,func_name)();
    }

    bar(new Foo(), Foo.prototype.anyfunc.name);

也许这不是你所要求的,但它应该是这样的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM