Передача класса метода в качестве параметра в Typescript

Я ищу возможность передать метод класса функции, которая затем может выполнить эту функцию в экземпляре этого класса. Что-то вроде этого псевдокода: (обратите внимание, что это абстрактный пример)

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

function bar(obj: Foo ,func: "Foo.method") {  // "that 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

но это касается статических функций, которые я не хочу.

Ответ 1

Это не проверяет время компиляции, что функция пришла из 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

Я предполагаю, что вы ищете какой-то способ для компилятора 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

Ответ 3

Да, объявите функцию следующим образом:

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

Назовите его так: typescript:

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

Или из javascript:

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

Также вы можете передать метод:

myfunction(this.someMethod);

Ответ 4

Typescript решение 2+

TL; DR: Typescript Игровая площадка, "Репо с демо"

Преимущества:

  • Проверка времени компиляции.
  • Не позволит вам потерять контекст this, если передача метода экземпляра.
  • Не теряйте производительность: не нужно объявлять методы класса как методы экземпляра (например, public somefunc = () => { return this.prop; }) - Подробнее....
  • Не связывайтесь с прототипом класса.
  • Согласованный шаблон подписи: передача обратного вызова в качестве первого arg и 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 Справочник:

Ответ 5

Javascript разрешил бы это, но не уверен, что это то, что вы хотите?

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

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

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