Get Off My Lawn Get Off My Lawn - 3 months ago 38
TypeScript Question

Generics get class name

I have a generic function that I would like to get the name of the class that is passed in.

public addComponent<T extends Component>(): Component {
comp = new Component() as T;
comp.name = T.constructor.name;
console.log(comp.name);
return comp;
}


Then lets say I call it like so:

obj.addComponent<MyClass>();


I would then expect the log to display "MyClass". But currently I get an error saying:


Cannot find name 'T'.

Answer

There's no way to do that.

The T doesn't exist at runtime, it's only for compilation and the compiler removes that (along with the types) so the resulting javascript for this:

class MyFactory {
    public addComponent<T extends Component>(): Component {
        let comp = new Component() as T;
        comp.name = T.constructor.name;
        console.log(comp.name);
        return comp;
    }
}

Is:

var MyFactory = (function () {
    function MyClass() {
    }
    MyFactory.prototype.addComponent = function () {
        var comp = new Component();
        comp.name = T.constructor.name;
        console.log(comp.name);
        return comp;
    };
    return MyFactory;
}());

As you can see, the js code doesn't have the generics signature, so there's no definition for T, and so T.constructor results in the error you're receiving.

If you want the method to create an instance of a class by passing it then it should look like:

interface ComponentConstructor<T extends Component> {
    new(): T;
    name: string;
}

class Component {
    name: string;
}

class MyComponent extends Component {}

class MyFactory {
    public addComponent<T extends Component>(ctor: ComponentConstructor<T>): Component {
        let comp = new ctor();
        comp.name = ctor.name;
        console.log(comp.name);
        return comp;
    }
}

let factory = new MyFactory();
let obj = factory.addComponent(MyComponent as ComponentConstructor<MyComponent>);

(code in playground)