9

For example if we have a class like this:

class MyClass {
  className: string;
}

Is it possible to get 'MyClass' assigned to className property at compile time?

EDIT: already tried this.constructor.name. However, latter doesnt help with minified code. Hence checking if there is a way to capture class name when typescript code is compiled to JS. I'm using angular-cli.

Benny Bottema
  • 11,111
  • 10
  • 71
  • 96
cynx
  • 387
  • 1
  • 3
  • 14

3 Answers3

9

/additional answer

Since you need the actual name of the original class even after uglifying, you will need to look into your build process instead.

You say you use angular-cli, which uses UglifyJS under the hood for uglifying. UglifyJS supports a flag for keeping the original Class names, or even a whitelist of class names that should be ignored. Specifically it is the mangler portion you are interested in. The official website even mentions it will break code using Function.name.

You can completely disable mangling, or you can specifically disable mangling class names (or white list certain class names). I don't think this is possible with angular-cli (in webpack you can), but the flag you are looking for is keep-classnames or keep_fnames. However, the angular-cli team has indicated multiple times it won't support configuration on this granular level.

So then you have two options left it seems:

  1. switch to full webpack (ng eject can help you with this)
  2. hard code the class names

Like so:

class MyClass {
  className = 'MyClass';
}

What is ng eject? Quoting dave11mj's comment:

ng eject simply means you need to do something a lot more advance or custom with webpack than what the cli provides for commands like ng build and ng serve .. So it generates a webpack.config.js based on the configurations that the cli uses, so that you can then customize it further.

So it certainly sounds like it was made for your case as long as angular-cli doesn't natively support configuration for UglifyJS.


/original answer (still useful with UglifyJs mangling disabled)

class MyClass {
  className = this.constructor.name;
}

const instance = new MyClass();
console.info(instance.className); // yields "MyClass"

If you use TypeScript >= 2.1, the type string is inferred by the compiler.

jsFiddle

If you have a constructor anyway, you can also define it like this and omit the explicit field completely (matter of preference, both work the same):

class MyClass {
  constructor(public className = this.constructor.name) {
    (..)
  }
}
Benny Bottema
  • 11,111
  • 10
  • 71
  • 96
  • Thanks for this. I have decided to go ahead with hard coded strings for now. However, still hoping Typescript includes a similar compile time feature. Will update this space if come across something more elegant in future. – cynx Jan 26 '18 at 17:05
  • `this` cannot be referenced in the constructor – Pian0_M4n Jul 31 '19 at 07:28
0

You could use the constructor to make a variable:

constructor() {
  public c : string = this.constructor.name;
}
rrd
  • 5,789
  • 3
  • 28
  • 36
  • 2
    Tried this, but this doesn’t work when code is minified. Hence looking to capture this as compile time – cynx Jan 25 '18 at 09:01
-1

I know this is a little old now but I ran into the same problem and couldn't find a good solution. I did not want to use ng eject to turn off or whitelist mangling so I did this to workaround it. Instead of using this.constructor.name I created a function to return the object type for me. You do have to know which classes you want and list each of them in the function with the instanceof operator. The function looks like this:

function getType(o: any):string
{
    if (o instanceof MyClass1)
        return 'MyClass1';
    else if (o instanceof MyClass2)
        return 'MyClass2';
    else
        return null; // class doesn't exist.
}

To use the function you'd call it like this:

MyClass1 = myClass1;
// instead of this:
console.log(myClass1.constructor.name);
// call this:
console.log(getType(myClass1));

So in your case, to run it at compile time you could do this:

class MyClass {
  className: string = getType(this); // or set the value in a constructor
}
Asheq Reza
  • 87
  • 1
  • 7