¿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"
¿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"
Respuestas:
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.
let instance: any = this.constructor; console.log(instance.name);
anyesconsole.log(instance.constructor['name']);
interface Function { name: string; }esto ampliará la definición "nativa".
MyClass.nameno funcionará bien si está minimizando su código. Porque minimizará el nombre de la clase.
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.
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.
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.
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"
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"
Property 'name' does not exist on type 'Function'.
(this as {}).constructor.nameo (this as object).constructor.namees mejor que anyporque entonces realmente obtienes autocompletar :-)
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.
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; }
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] : "";
}
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);
}
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
}