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

pgx2nnw8  于 2023-05-30  发布在  TypeScript
关注(0)|答案(8)|浏览(197)

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

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

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

fzsnzjdm

fzsnzjdm1#

这不会在编译时检查函数是否来自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
cyvaqqii

cyvaqqii2#

Typescript 2+解决方案

TL;DR:TypeScript Playground,Repo with a demo

优点:
1.编译时检查。
1.在传递示例的方法时不会丢失this上下文。
1.不损失性能:不需要将类的方法声明为示例方法(e. g. public somefunc = () => { return this.prop; })-了解更多信息。
1.不要破坏类的原型。
1.一致的签名模式:将回调作为第一个参数传递,将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参数
1.函数重载

  1. Generics
ymzxtsji

ymzxtsji3#

我假设你正在寻找某种方法让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
vc6uscn9

vc6uscn94#

是的,像这样声明函数:

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

从typescript中这样调用它:

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

或者从javascript:

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

你也可以通过方法:

myfunction(this.someMethod);
svgewumm

svgewumm5#

就我而言;根据问题的陈述,我可以这样做:

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'

此外,我应该指出,我是从这个明确的解释中得到启发的。
希望能帮上忙!

31moq8wy

31moq8wy6#

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

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

o3imoua47#

JavaScript允许这样做,但不确定这是否是你想要的。

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

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

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

nbewdwxp8#

在我看来,你应该使用门面设计模式为这种情况。
当您创建一个复杂的库、工具或系统,由许多函数和/或类组成时;它变得难以理解和依赖。所以你应该实现一个提供简单统一接口的类。

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);

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

相关问题