Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript/Javascript: Call function by string name

I have a *.ts file with lots of exported functions like:

export function newItemFoo() {
    return {foo: 0, bar: '', baz: true};
}

export function newItemBar() {
    return {foo: 0, bar: ''};
}

export function newItemXXX() {
    return {xxx: 0};
}

I want to make a "magic method" (in the same *.ts) that can call one of those methods by name, eg:

export function magicMethod(name: string) {
    const newEmptyFunc = new Function(`return new${name}()`);
    return newEmptyFunc();
}
magicMethod('ItemFoo');

but it raise an error

Error: newItemFoo is not defined

It works with eval:

export function magicMethod(name: string) {
    return eval(`newEmpty${name}()`);
}
magicMethod('ItemFoo');

How do I call a function by string name with new Function()?

like image 344
ar099968 Avatar asked Mar 02 '23 08:03

ar099968


1 Answers

Both using eval() and new Function() are convoluted ways to achieve the goal.

Try a simpler approach . Create an object that provides a mapping between the values you want to pass to magicMethod() and the functions to be called. Then implement magicMethod() this way:

function newItemFoo() {
    return {foo: 0, bar: '', baz: true};
}

function newItemBar() {
    return {foo: 0, bar: ''};
}

function newItemXXX() {
    return {xxx: 0};
}

const magicWand: { [K: string]: Function } = {
   Foo: newItemFoo,
   Bar: newItemBar,
   xxx: newItemXXX,   // this allows you to use a different value for the argument
   yyy: newItemXXX,   // ... to use multiple names for the same function
                      // ... and to handle gracefully the calls of non-existing functions 
};

export function magicMethod(name: string) {
  if (magicWand[name]) {
    return magicWand[name]();
  }

  throw new Error(`Method '${name}' is not implemented.`);
}

Usage:

magicMethod('Foo')
// { foo: 0, bar: '', baz: true }
magicMethod('Bar')
// { foo: 0, bar: '' }
magicMethod('xxx')
// { xxx: 0 }
magicMethod('yyy')
// { xxx: 0 }
magicMethod('zzz')
// Error: Method 'zzz' is not implemented.

However, if you provide such a mechanism to invoke the functions defined by the module you probably don't want to make them public using the standard export mechanism but only though magicMethod(). It is the only function that needs to be export-ed.

like image 137
axiac Avatar answered Mar 05 '23 16:03

axiac