Obtener el nombre de la clase de un objeto en tiempo de ejecución


272

¿Es posible obtener el nombre de clase / tipo de un objeto en tiempo de ejecución usando TypeScript?

class MyClass{}

var instance = new MyClass();
console.log(instance.????); // Should output "MyClass"

3
Ver aquí . En tiempo de ejecución estás ejecutando JavaScript.
Matt Burland el

1
¿Cómo se obtiene el nombre del constructor en el archivo TypeScript? No puede hacer esto.constructor.name en un método TypeScript (en el archivo .ts).
sheldon_cooper

Respuestas:


464

Respuesta simple:

class MyClass {}

const instance = new MyClass();

console.log(instance.constructor.name); // MyClass
console.log(MyClass.name);              // MyClass

Sin embargo: tenga en cuenta que es probable que el nombre sea diferente al usar código minificado.


14
Desafortunadamente, MyClass.name es una característica de ES6, por lo tanto, no funciona en IE11.
comenzó

9
mecanografiado arrojará un error en esto. debería hacerlet instance: any = this.constructor; console.log(instance.name);
Subash

77
@Subash una manera más concisa para evitar la proyección de anyesconsole.log(instance.constructor['name']);
Nick Strupat

1
@Subash También podría crear una declaración de tipo en su lugar: interface Function { name: string; }esto ampliará la definición "nativa".
John Weisz

1
MyClass.nameno funcionará bien si está minimizando su código. Porque minimizará el nombre de la clase.
AngryHacker

28

Sé que llego tarde a la fiesta, pero creo que esto también funciona.

var constructorString: string = this.constructor.toString();
var className: string = constructorString.match(/\w+/g)[1]; 

Alternativamente...

var className: string = this.constructor.toString().match(/\w+/g)[1];

El código anterior obtiene todo el código del constructor como una cadena y aplica una expresión regular para obtener todas las 'palabras'. La primera palabra debe ser 'función' y la segunda palabra debe ser el nombre de la clase.

Espero que esto ayude.


44
Lo siento, claro. Por lo general, utiliza minificación, fecalificación y otros sistemas de procesamiento posterior. Entonces, en el servidor de producción, su nombre de clase no será el mismo. Y tu código no funcionará. No encontré una solución realmente buena para obtener el nombre de la clase. La forma más adecuada es definir una variable estática con su nombre de clase.
Dima Kurilo

23

Mi solución no fue confiar en el nombre de la clase. object.constructor.name funciona en teoría. Pero si está usando TypeScript en algo como Ionic, tan pronto como vaya a producción, se incendiará porque el modo de producción de Ionic minimiza el código Javascript. Entonces las clases reciben nombres como "a" y "e".

Lo que terminé haciendo fue tener una clase typeName en todos mis objetos a los que el constructor asigna el nombre de la clase. Entonces:

export class Person {
id: number;
name: string;
typeName: string;

constructor() {
typeName = "Person";
}

Sí, eso no fue lo que se preguntó, realmente. Pero usar el constructor.name en algo que podría minimizarse en el futuro es solo un dolor de cabeza.


19

Ver esta cuestión .

Dado que TypeScript está compilado en JavaScript, en tiempo de ejecución está ejecutando JavaScript, por lo que se aplicarán las mismas reglas.


14

Primero debe convertir la instancia en anyporque Functionla definición de tipo no tiene una namepropiedad.

class MyClass {
  getName() {
    return (<any>this).constructor.name;
    // OR return (this as any).constructor.name;
  }
}

// From outside the class:
var className = (<any>new MyClass()).constructor.name;
// OR var className = (new MyClass() as any).constructor.name;
console.log(className); // Should output "MyClass"

// From inside the class:
var instance = new MyClass();
console.log(instance.getName()); // Should output "MyClass"

Actualizar:

Con TypeScript 2.4 (y potencialmente anterior) el código puede ser aún más limpio:

class MyClass {
  getName() {
    return this.constructor.name;
  }
}

// From outside the class:
var className = (new MyClass).constructor.name;
console.log(className); // Should output "MyClass"

// From inside the class:
var instance = new MyClass();
console.log(instance.getName()); // Should output "MyClass"

2
Intenté con TypeScript 2.6.2 y Property 'name' does not exist on type 'Function'.
obtengo

(this as {}).constructor.nameo (this as object).constructor.namees mejor que anyporque entonces realmente obtienes autocompletar :-)
Simon_Weaver

5

En Angular2 esto puede ayudar a obtener el nombre de los componentes:

    getName() {
        let comp:any = this.constructor;
        return comp.name;
    }

comp: se necesita cualquiera porque la compilación de TypeScript emitirá errores, ya que la función inicialmente no tiene un nombre de propiedad.


55
sin embargo, esto no funcionará si minimiza / uglifica su código
Admir Sabanovic

para obtener un 'nombre' utilizable de un componente, es mejor que obtenga el tagName de element.nativeElement: en una directiva, puede obtener el nombre del componente como este @Optional() element: ElementRef<HTMLElement>y luego usar if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
Simon_Weaver

(y los nombres de las etiquetas no se minimizan)
Simon_Weaver

4

El código completo de TypeScript

public getClassName() {
    var funcNameRegex = /function (.{1,})\(/;
    var results  = (funcNameRegex).exec(this["constructor"].toString());
    return (results && results.length > 1) ? results[1] : "";
}

44
Puede tener algunos problemas si minimiza y optimiza su código mecanografiado / javascript. Puede cambiar los nombres de las funciones y luego la comparación del nombre de su clase puede ser incorrecta.
Antti

4
  • Tenido que añadir " prototipo. " Para su uso: myClass.prototype.constructor.name.
  • De lo contrario, con el siguiente código: myClass.constructor.nametuve el error TypeScript:

error TS2339: Property 'name' does not exist on type 'Function'.


0

Esta solución funciona después de la uglificación de minificación, pero requiere decorar las clases con metadatos.

Utilizamos la generación de código para decorar nuestras clases de entidad con metadatos de la siguiente manera:

@name('Customer')
export class Customer {
  public custId: string;
  public name: string;
}

Luego consumir con el siguiente ayudante:

export const nameKey = Symbol('name');

/**
 * To perserve class name though mangling.
 * @example
 * @name('Customer')
 * class Customer {}
 * @param className
 */
export function name(className: string): ClassDecorator {
  return (Reflect as any).metadata(nameKey, className);
}

/**
 * @example
 * const type = Customer;
 * getName(type); // 'Customer'
 * @param type
 */
export function getName(type: Function): string {
  return (Reflect as any).getMetadata(nameKey, type);
}

/**
 * @example
 * const instance = new Customer();
 * getInstanceName(instance); // 'Customer'
 * @param instance
 */
export function getInstanceName(instance: Object): string {
  return (Reflect as any).getMetadata(nameKey, instance.constructor);
}

-2

Si ya sabe qué tipos esperar (por ejemplo, cuando un método devuelve un tipo de unión ), puede usar protectores de tipo.

Por ejemplo, para los tipos primitivos puede usar un tipo de protección :

if (typeof thing === "number") {
  // Do stuff
}

Para tipos complejos puede usar una instancia de guardia :

if (thing instanceof Array) {
  // Do stuff
}

Supongo que es porque tu respuesta no está relacionada con la pregunta. La pregunta era obtener el nombre de la clase para no hacer condicionalmente cosas en el tipo de instancia.
Daniel Leiszen
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.