É possível obter o nome da classe / tipo de um objeto em tempo de execução usando o TypeScript?
class MyClass{}
var instance = new MyClass();
console.log(instance.????); // Should output "MyClass"
É possível obter o nome da classe / tipo de um objeto em tempo de execução usando o TypeScript?
class MyClass{}
var instance = new MyClass();
console.log(instance.????); // Should output "MyClass"
Respostas:
class MyClass {}
const instance = new MyClass();
console.log(instance.constructor.name); // MyClass
console.log(MyClass.name); // MyClass
No entanto: lembre-se de que o nome provavelmente será diferente ao usar código minificado.
let instance: any = this.constructor; console.log(instance.name);
anyéconsole.log(instance.constructor['name']);
interface Function { name: string; }- isso estenderá a definição "nativa".
MyClass.namenão funcionará bem se você estiver minificando seu código. Porque ele reduzirá o nome da classe.
Sei que estou atrasado para a festa, mas acho que isso também 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];
O código acima obtém todo o código do construtor como uma sequência e aplica uma expressão regular para obter todas as 'palavras'. A primeira palavra deve ser 'função' e a segunda palavra deve ser o nome da classe.
Espero que isto ajude.
Minha solução foi não confiar no nome da classe. object.constructor.name trabalha em teoria. Mas se você estiver usando o TypeScript em algo como o Ionic, assim que você começar a produção, ele ficará em chamas porque o modo de produção do Ionic reduz o código Javascript. Portanto, as classes recebem nomes como "a" e "e".
Acabei fazendo uma classe typeName em todos os meus objetos aos quais o construtor atribui o nome da classe. Assim:
export class Person {
id: number;
name: string;
typeName: string;
constructor() {
typeName = "Person";
}
Sim, não foi o que foi perguntado, realmente. Mas usar o constructor.name em algo que pode ser minificado no futuro é apenas implorar por uma dor de cabeça.
Veja esta pergunta .
Como o TypeScript é compilado para JavaScript, no tempo de execução, você está executando o JavaScript, portanto as mesmas regras serão aplicadas.
Você precisa converter primeiro a instância anyporque Functiona definição de tipo não possui uma namepropriedade.
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"
Com o TypeScript 2.4 (e potencialmente anterior), o código pode ser ainda mais limpo:
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.nameou (this as object).constructor.nameé melhor do que anyporque, na verdade, você obtém o preenchimento automático :-)
No Angular2, isso pode ajudar a obter o nome dos componentes:
getName() {
let comp:any = this.constructor;
return comp.name;
}
comp: any é necessário porque a compilação do TypeScript emitirá erros, já que Function inicialmente não possui nome de propriedade.
element.nativeElement- Em uma diretiva, você pode obter o nome do componente como este @Optional() element: ElementRef<HTMLElement>e depois usá if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
O código TypeScript completo
public getClassName() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(this["constructor"].toString());
return (results && results.length > 1) ? results[1] : "";
}
Essa solução funciona após a uglificação da minificação, mas requer a decoração das classes com metadados.
Usamos a geração de código para decorar nossas classes de entidade com metadados da seguinte forma:
@name('Customer')
export class Customer {
public custId: string;
public name: string;
}
Em seguida, consuma com o seguinte auxiliar:
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);
}
Se você já sabe quais tipos esperar (por exemplo, quando um método retorna um tipo de união ), pode usar protetores de tipo.
Por exemplo, para tipos primitivos, você pode usar um tipo de proteção :
if (typeof thing === "number") {
// Do stuff
}
Para tipos complexos, você pode usar uma instância de guarda :
if (thing instanceof Array) {
// Do stuff
}