Julian Le Calvez Julian Le Calvez - 11 days ago 7
TypeScript Question

Typescript static methods inheritance

I'm working on an ionic 2 project using typescript 2.0.6.

I have a Base class which manage some behaviors and I inherit several classes from this base class.
And I want to be able to get the name of the actual class (not the base one).

Here is my code :

export class AbstractModel {
oneInstanceMethod() {
this.getClassName();
}
static oneStaticMethod() {
this.getClassName();
}
getClassName() {
return (<any>this).constructor.name;
}
static getClassName() {
return (<any>this).name;
}
}

export class MyClass1 extends AbstractModel {

}
export class MyClass2 extends AbstractModel {

}


And I have 2 kind of calls : Either
MyClass1.oneStaticMethod()
or
(new MyClass2).oneInstanceMethod()
.

My problem is that this code was working before (now I get 'e' because it returns the function e()) I made some upgrade in my ionic project. I think my typescript version has been upgraded (i'm not sure but I think it was the 1.8 before).

How can I solve this ? I tried many things (like creating variables to store the values, but neither works in static mode AND instance mode).

Thanks !

Answer

If I copy your code ad verbatim and add:

var a = new MyClass1();
var b = new MyClass2();

document.body.innerHTML = a.getClassName() + " - " + b.getClassName();

Then it runs as you expect.

The issue you're experiencing is most likely due to minification. Your class names get garbled in minification. Most minifiers have an option to disable renaming of classes/functions, you haven't mentioned which one you use but surely their docs say something about this. It will increase file size though.

You clarified a bit in comments, and I'd still recommend not using class names, but prefer being explicit about this kind of thing. With Typescript you gain tooling support for automated renames, but you kinda throw that away again. Then again, that's your own design decision to make.


Footnote: here's a solution that might be useful or not, depending on your design preferences. It dispatches the knowledge on associated table name to an instance variable:

class AbstractModel {
  _tableName: string = null;

  getClassName = () => {
    if (!this._tableName) {
      throw new Error("No table name was set for this DTO.");
    }
    return this._tableName;
  }
}

class MyClass1 extends AbstractModel {
    _tableName = "MyTable1";
}

class MyClass2 extends AbstractModel {
    _tableName = "AnotherTable2";
}

var a = new MyClass1();
var b = new MyClass2();

document.body.innerHTML = a.getClassName() + " - " + b.getClassName();

See it in action on jsfiddle.

Note that I also snuck in this:

getClassName = () => {

vs

getClassName() {

So that this is correctly captured and refers to the class instance, not the function that's executing.