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"
Adam Mills
fonte
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.

Mikael Couzic
fonte
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.


fonte
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.

SonOfALink
fonte
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.

Matt Burland
fonte
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"
Westy92
fonte
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.

Admir Sabanovic
fonte
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] : "";
}
Nati Krisi
fonte
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'.

Flox
fonte
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);
}
ttugates
fonte
-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
}
Cocowalla
fonte
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