Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get intance's class in TypeScript

How to get the class of an instance in TypeScript? This question is similar to Get an object's class name at runtime in TypeScript but I don't want to get the class name. I want to get the class itself.

What I need this for? TypeScript does not have class methods, only static methods. But they are not virtual. In order to fully translate my mental model into Js code, I need to have virtual class methods.

My idea is to do something like this:

function classOf<T>(o: T) : any {
    return o.class; // How to write this???
}

class Foo {
    static tryMe() : string {
        return "foo";
    }

}

class Bar extends Foo {
    static tryMe() : string {
        return "bar";
    }

}

function testPolymorphClassMethod(instance : Foo) {
    console.log(classOf(instance).tryMe());
}

testPolymorphClassMethod(new Foo()); // Should print "foo"
testPolymorphClassMethod(new Bar()); // Should print "bar"

Whenever a concrete class is available, I could call its static method directly. If only an instance is available, I would like to call the static method of its class, e.g. making it virtual by hand.

The problem is that I have no idea how to write the classOf function. It may not be possible at all.

I was also trying this:

function classOf<T>(o: T) : typeof T {
    return typeof o;
}

But it gives a comiple error:

"T only refers to a type, but it is used as value here".

I know that functions are first class objects in JavaScript (and also TypeScript). But TypeScript classes may not be, and then maybe it will be impossible to do what I want.

Is there a workaround for this that does not require typing lots of code for each and every descendant class?

The closest thing I could get is:

class Virtualizer {
    virtual(methodName: string) : any {
        return eval(this.constructor.name+"."+methodName);
    }
}

class Foo extends Virtualizer {
    static getMyName() : string {
        return "foo";
    }

    public test() : string {
        return this.virtual("getMyName")();
    }

}

class Bar extends Foo {
    static getMyName() : string {
        return "bar";
    }    
}

let foo = new Foo();
let bar = new Bar();

console.log(foo.test()); // Prints "foo"
console.log(bar.test()); // Prints "bar"

But this looses all type information, it needs a common base class (or code repetition), and I can never call the actual method that I want to call, just a "virtualizer". It is so clumsy.

I could extract the class related information into an encapsulated singleton object, but that will require me to change visibility of many methods from protected to public. (And also generate lots of cross references between the main and the encapsulated objects, very clumsy too.)

like image 545
nagylzs Avatar asked Jan 25 '18 07:01

nagylzs


Video Answer


1 Answers

You can return constructor property of your o

function classOf<T>(o: T): any {
    return o.constructor;
}

See Demo

like image 120
Suren Srapyan Avatar answered Sep 22 '22 06:09

Suren Srapyan