Obter o nome da classe de um objeto em tempo de execução


271

É 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"

3
Veja aqui . No tempo de execução, você está executando o JavaScript.
Matt Burland

1
Como você obtém o nome do construtor no arquivo TypeScript? Você não pode fazer this.constructor.name em um método TypeScript (no arquivo .ts).
224126 sheldon_cooper

Respostas:


462

Resposta simples:

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.


14
Infelizmente MyClass.name é um recurso do ES6, portanto, não funciona no IE11.
begie

9
O texto datilografado lançará um erro nisso. deve fazerlet instance: any = this.constructor; console.log(instance.name);
Subash

7
@Subash uma maneira terser para evitar vazamento de anyéconsole.log(instance.constructor['name']);
Nick Strupat

1
@Subash Você também pode criar uma declaração de tipo: interface Function { name: string; }- isso estenderá a definição "nativa".
John Weisz

1
MyClass.namenão funcionará bem se você estiver minificando seu código. Porque ele reduzirá o nome da classe.
AngryHacker 5/08/19

28

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.


4
Desculpe, claro. Geralmente, você usa minificação, feio e outros sistemas de pós-processamento. Portanto, no servidor de produção, o nome da sua classe não será o mesmo. E seu código não funcionará. Não encontrei uma solução muito boa para obter o nome da classe. A maneira mais adequada é definir uma variável estática com o nome da sua classe.
Dima Kurilo

23

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.


19

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.


14

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"

Atualizar:

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"

2
Tentei no TypeScript 2.6.2 e estou recebendo este erro:Property 'name' does not exist on type 'Function'.
orad

(this as {}).constructor.nameou (this as object).constructor.nameé melhor do que anyporque, na verdade, você obtém o preenchimento automático :-)
Simon_Weaver 16/01

5

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.


5
no entanto, isso não funcionará se você minificar / modificar o código
Admir Sabanovic 22/12/16

para obter um 'nome' utilizável de um componente, é melhor você obter o tagName de 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; }
lo

(e os nomes das tags não são minificados)
Simon_Weaver 16/01/19

4

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] : "";
}

4
Você pode ter alguns problemas se minimizar e otimizar seu código de texto / javascript. Isso pode alterar os nomes das funções e a comparação do nome da classe pode estar errada.
Antti

4
  • Tinha a acrescentar " protótipo. " Para uso: myClass.prototype.constructor.name.
  • Caso contrário, com o seguinte código myClass.constructor.name:, tive o erro TypeScript:

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


0

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);
}

-2

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
}

Eu acho que é porque sua resposta não está relacionada à pergunta. A questão era obter o nome da classe para não fazer Condicionalmente coisas no tipo de instância.
Daniel Leiszen
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.