0

Based on this https://stackoverflow.com/a/46656181/8577819, I have created a function to return an object for a class.

function getInstance<T extends Object>(type: (new (...args: any[]) => T), ...args: any[]): T {
    return new type(...args);
}

class testclass {
    x: string;
    constructor(x:string) {
        this.x=x;
    }
    printcon() {
        console.log("printing from test " + this.x);
    }
}

var dds: testclass = getInstance(testclass,10);
dds.printcon();

/// Console prints 
// printing from test 10

Is it possible to pass the class name itself as a string argument to the object creator?

clnm: string = "testclass";
var dds2: <clnm> = getInstance(clnm,10);
dds2.printcon();
ProgrammerPer
  • 1,125
  • 1
  • 11
  • 26
natrayan
  • 345
  • 2
  • 11

3 Answers3

2

I have accomplished the same task by using following similar code:

Assuming we have to create a Instance of classes located under modules folder.

modules/Calulator.ts which takes an argument too in constructor:

export class Calculator {

    c: number;

    constructor(cc: number) {
        this.c = cc;
    }
    sum(a: number, b: number): number {
        return a + b + Number(this.c);
    }
}

Our InstanceBuilder class without using eval (Commented working code using eval too):

import * as wfModule from "../modules";
export class InstanceBuilder {

    getInstance(className: string, ...args: any[]): any {

        // TODO: Handle Null and invalid className arguments
        const mod: any = wfModule;
        if (typeof mod[className] !== undefined) {
            return new mod[className](args);
        } else {
            throw new Error("Class not found: " + className);
        }

        // Other working methods:
        // const proxy: any = undefined;
        // const getInstance = (m) => eval("obj = Object.create(m." + className + ".prototype);");
        // eval("obj = new mod['" + className + "'](" + args + ")");
        // eval("proxy.prototype = Object.create(mod." + className + ".prototype);");
        // obj.constructor.apply(args);
    }
}

Then, to create the class dynamically, you could do the following:

const instanceBuilder = new InstanceBuilder();
const commandInstance = instanceBuilder.getInstance("Calculator", initArgsValues);

The above solution should work (but not tested it for all the use cases, but should help you get started.)

Sagar Chilukuri
  • 1,430
  • 2
  • 17
  • 29
1

I would recommend creating a map of possible options:

const availableClasses = {
    testclass: testclass,
    anyOtherName: SomeClass
};

function getInstanceByName(name, ...args) {
    const Class = availableClasses[name];
    return getInstance(Class, ...args);
}

// Usage:
// getInstanceByName('testclass', 10)
// getInstanceByName('anyOtherName', 10)

If you really want to use dynamic call, which I will not recommend it (due to security concerns), but you may use:

function getInstanceByName(name, ...args) {
    const Class = eval(name);
    return getInstance(Class, ...args);
}

// Usage:
// getInstanceByName('testclass', 10)

// But it is not safe, as you may exploit it as well:
// getInstanceByName('function () { alert("abc"); }')
Dawid Rusnak
  • 527
  • 3
  • 13
0

You don't have to send the name manually. You can get the class name using the constructor property

class testclass {
  x;
  constructor(x) {
    this.x = x;
  }
  printcon() {
    console.log("printing from test " + this.x);
  }
}

const instance = new testclass(10)
instance.printcon()

// name of the constructor or class it was created from
console.log(instance.constructor.name)
adiga
  • 34,372
  • 9
  • 61
  • 83