0

I recently started working on a game in cocos creator which uses TypeScript/JavaScript as a language, which I'm new to. I'm trying to create a complex callback method that will call methods attached to an array of objects.

Here is a short example of the functionality I'm hoping to achieve:

let arr:Base[] = [new Foo(), new Bar(), new FooBar()];

function func(interfaceType, method) {
    arr.forEach(element => {
        if(element instanceof interfaceType){
            console.log(element.method());
        }   
    });
}

func(BarI, bar()); //This should output bar foobar
func(FooI, foo()); //This should output 1 2

And all the interface and class implementations

interface FooI{
    foo():number;
    foo2():string;
}

interface BarI{
    bar():string;
}

class Base { }

class Foo extends Base implements FooI{
    foo(): number {
        return 1;
    }
    foo2(): string {
        return "A";
    }
}

class Bar extends Base implements BarI{
    bar(): string {
        return "bar";
    }
}

class FooBar extends Base implements FooI, BarI{
    foo(): number {
        return 2;
    }
    foo2(): string {
        return "B";
    }
    bar(): string {
        return "foobar";
    }
}

This block of code has a lot of problems, like instanceof doesn't work for interfaces, that's not a huge problem, I have figured out a couple workarounds (not the most elegant, but not a huge problem). The real trouble I'm having is calling the method, I looked around and found code for passing functions/methods as a parameter, but it runs the parameter as an independent function rather than an object's implemented method.

I got this example working using reflections in Java if you want to see a working example: Pastebin Link

  • Haven't been able to try it out too much, but you'd probably need to use the square bracket syntax to access members dynamically. Eg: `element[methodName]();` Where methodName here is a string like "foo" – Narek Daduryan Dec 20 '20 at 02:05
  • Thank you so much, that worked perfectly, it was exactly what I needed! If you submit this as answer I'll mark it as such. – YabaiPanda Dec 20 '20 at 02:51
  • in the first place you can't use types as values. – Rogelio Dec 20 '20 at 03:18

2 Answers2

0

Unfortunately you can't do

interface BarI{
    bar():string;
}

if(element instanceof IBar) ...

since interfaces aren't "real" js code. You could do

class BarI{
    bar(): string {
        ...
    }
}

var element = new IBar()

if(element instanceof IBar) ...

I hope that helps! This has some good info as well

Frank
  • 735
  • 1
  • 12
  • 33
0

Thanks to Narkek Daduryan for the answer. I ended up doing

let arr:Base[] = [new Foo(), new Bar(), new FooBar()];

function func(methodName) {
    arr.forEach(element => {
        if(element[methodName] !== undefined){
            console.log(element[methodName]());
        }   
    });
}

func("bar"); //This correctly output bar foobar
func("foo"); //This correctly output 1 2

It also cuts out the need to check for interfaces which is fine because there is no overlap for method names while calling the appropriate methods.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131