user3395924
user3395924

Reputation: 135

Angular / Typescript class.name does not work in production build

Using Angular 5. Facing a weird issue with class.name property. We have the following function in typescript:

export class ApiService
{
  public list<T>(c: new(values: Object)=> T)
  {
    var cname = c.name;
    ....
  }
}

Now, if I use this function in dev build of Angular (ng-build) like the following:

export class Employee()
{
    public id:string;
    public name: string;

    constructor(values: Object = {}) {          
       Object.assign(this, values);          
    }
}

And in code somewhere:

var list = api.list(Employee);

The above works, and in the list function I get cname = 'Employee'

However, if we build this solution using ng build --env=prod, the code fails and we get cname = undefined.

Why is this happening, and how to resolve it ? Shouldn't something that compiles and works in dev build, work in production ?

Upvotes: 8

Views: 4256

Answers (2)

Vincenzo Bonsangue
Vincenzo Bonsangue

Reputation: 1

Had the same issue with production code where 'constructor.name' was returning an empty string. My solution was to decorate the classes I needed where the decorator would reassign 'name' at run time with an arbitrary class-name or one passed thru as a parameter: here is the decorator:

import "reflect-metadata";
var __global__ClassName__id__ = 0;
export function ClassName(useThisName: string = null) {
    return function (target: any) {
       if (target.name.length === 0 || useThisName !== null) {
            Object.defineProperty(target, "name", {
                value: useThisName !== null ? useThisName : `__ClassName__${++__global__ClassName__id__}`,
                enumerable: false,
                writable: false,
                configurable: true
            });
        }
    }
}

and code would look like this:

// generate a dynamic class name
@Decorator.ClassName()
export class PopupMessage{ }

// uses the argument as class name
@Decorator.ClassName("PopupMessage")
export class PopupMessage{ }

// and code will work as usual
var something = new Message.PopupMessage(1);
var samething = (<any>something).constructor.name == Message.PopupMessage.name;

Upvotes: 0

Nathan Friend
Nathan Friend

Reputation: 12814

You are likely running into an issue with minification, which only occurs during a prod build. Minification will rename your classes in order achieve the smallest output file size.

See this question and answer for a related discussion: Angular-cli : How to ignore class names from being minified

As the answer above mentions, in order to configure this option, you will need ng eject your app, which will allow you customize UglifyJS options (the library responsible for minification), but this will also prevent you from using some of the nice features of the Angular CLI (like ng build and ng serve).

See this GitHub comment for a description of ng eject: https://github.com/angular/angular-cli/issues/6302#issuecomment-301220770

Upvotes: 2

Related Questions