簡體   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