Récupère le nom de classe d'un objet lors de l'exécution

273

Est-il possible d'obtenir le nom de classe / type d'un objet lors de l'exécution en utilisant TypeScript?

class MyClass{}

var instance = new MyClass();
console.log(instance.????); // Should output "MyClass"
Adam Mills
la source
3
Voyez ici . Au moment de l'exécution, vous exécutez JavaScript.
Matt Burland
1
Comment obtenez-vous le nom du constructeur dans un fichier TypeScript? Vous ne pouvez pas faire this.constructor.name dans une méthode TypeScript (dans un fichier .ts).
sheldon_cooper

Réponses:

464

Réponse simple:

class MyClass {}

const instance = new MyClass();

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

Cependant: sachez que le nom sera probablement différent lors de l'utilisation de code minifié.

Mikael Couzic
la source
14
Malheureusement, MyClass.name est une fonctionnalité ES6 et ne fonctionne donc pas dans IE11.
début
9
dactylographiera une erreur à ce sujet. devrait fairelet instance: any = this.constructor; console.log(instance.name);
Subash
7
@Subash une manière laconique pour éviter la coulée à anyestconsole.log(instance.constructor['name']);
Nick Strupat
1
@Subash Vous pouvez également créer une déclaration de type à la place: interface Function { name: string; }- cela étendra la définition "native".
John Weisz
1
MyClass.namene fonctionnera pas bien si vous réduisez votre code. Parce que cela réduira le nom de la classe.
AngryHacker
28

Je sais que je suis en retard à la fête, mais je trouve que cela fonctionne aussi.

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

Alternativement ...

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

Le code ci-dessus obtient le code constructeur entier sous forme de chaîne et applique une expression régulière pour obtenir tous les «mots». Le premier mot doit être «fonction» et le deuxième mot doit être le nom de la classe.

J'espère que cela t'aides.


la source
4
Désolé, bien sûr. Habituellement, vous utilisez la minification, la laideur et d'autres systèmes de post-traitement. Ainsi, sur le serveur de production, le nom de votre classe ne sera pas le même. Et votre code ne fonctionnera pas. Je n'ai pas vraiment trouvé de bonne solution pour obtenir le nom de la classe. La façon la plus appropriée consiste à définir une variable statique avec le nom de votre classe.
Dima Kurilo
23

Ma solution était de ne pas compter sur le nom de la classe. object.constructor.name fonctionne en théorie. Mais si vous utilisez TypeScript dans quelque chose comme Ionic, dès que vous allez en production, cela va exploser car le mode de production d'Ionic minimise le code Javascript. Ainsi, les classes reçoivent des noms comme "a" et "e".

Ce que j'ai fini par faire était d'avoir une classe typeName dans tous mes objets auxquels le constructeur attribue le nom de classe. Alors:

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

constructor() {
typeName = "Person";
}

Oui, ce n'était pas vraiment ce qui avait été demandé. Mais utiliser le constructeur.nom sur quelque chose qui pourrait potentiellement être minifié en cours de route est juste un suppliant pour un mal de tête.

SonOfALink
la source
19

Voir cette question .

Étant donné que TypeScript est compilé en JavaScript, au moment de l'exécution, vous exécutez JavaScript, donc les mêmes règles s'appliqueront.

Matt Burland
la source
14

Vous devez d'abord convertir l'instance en anycar Functionla définition de type de n'a pas de namepropriété.

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"

Mettre à jour:

Avec TypeScript 2.4 (et potentiellement plus tôt), le code peut être encore plus propre:

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
la source
2
J'ai essayé TypeScript 2.6.2 et Property 'name' does not exist on type 'Function'.
j'obtiens
(this as {}).constructor.nameou (this as object).constructor.nameest mieux que anyparce que vous obtenez alors la saisie
semi-
5

Dans Angular2, cela peut aider à obtenir le nom des composants:

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

comp: any est nécessaire car la compilation TypeScript générera des erreurs car Function n'a initialement pas de nom de propriété.

Admir Sabanovic
la source
5
cependant cela ne fonctionnera pas si vous minimisez / uglifiez votre code
Admir Sabanovic
pour obtenir un «nom» utilisable d'un composant, vous feriez mieux d'obtenir le tagName element.nativeElement- Sur une directive, vous pouvez obtenir le nom du composant comme ceci @Optional() element: ElementRef<HTMLElement>, puis utiliser if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
Simon_Weaver
(et les noms de balises ne sont pas minifiés)
Simon_Weaver
4

Le code TypeScript complet

public getClassName() {
    var funcNameRegex = /function (.{1,})\(/;
    var results  = (funcNameRegex).exec(this["constructor"].toString());
    return (results && results.length > 1) ? results[1] : "";
}
Nati Krisi
la source
4
Vous pourriez rencontrer des problèmes si vous réduisez et optimisez votre code dactylographié / javascript. Cela pourrait changer les noms de fonctions et votre comparaison de noms de classe pourrait être erronée.
Antti
4
  • J'ai dû ajouter ". Prototype. » À l' utilisation: myClass.prototype.constructor.name.
  • Sinon avec le code suivant:, myClass.constructor.namej'ai eu l'erreur TypeScript:

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

Flox
la source
0

Cette solution fonctionne après uglification de minification mais nécessite de décorer les classes avec des métadonnées.

Nous utilisons la génération de code pour décorer nos classes d'entité avec des métadonnées comme ceci:

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

Consommez ensuite avec l'aide suivante:

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
la source
-2

Si vous savez déjà à quels types vous attendre (par exemple, lorsqu'une méthode renvoie un type d'union ), vous pouvez utiliser des gardes de type.

Par exemple, pour les types primitifs, vous pouvez utiliser un typeof guard :

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

Pour les types complexes, vous pouvez utiliser une instance de guard :

if (thing instanceof Array) {
  // Do stuff
}
Cocowalla
la source
Je suppose que c'est parce que votre réponse n'est pas liée à la question. La question était d'obtenir le nom de classe pour ne pas faire de choses conditionnellement sur le type d'instance.
Daniel Leiszen