Ottieni il nome della classe di un oggetto in fase di esecuzione


272

È possibile ottenere il nome di classe / tipo di un oggetto in fase di esecuzione utilizzando TypeScript?

class MyClass{}

var instance = new MyClass();
console.log(instance.????); // Should output "MyClass"

3
Vedi qui . In fase di esecuzione si esegue JavaScript.
Matt Burland,

1
Come si ottiene il nome del costruttore nel file TypeScript? Non è possibile eseguire this.constructor.name in un metodo TypeScript (nel file .ts).
sheldon_cooper,

Risposte:


463

Risposta semplice:

class MyClass {}

const instance = new MyClass();

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

Tuttavia: attenzione che il nome sarà probabilmente diverso quando si utilizza il codice minimizzato.


14
Purtroppo MyClass.name è una funzionalità ES6, quindi non funziona in IE11.
begie

9
dattiloscritto genererà un errore in questo. dovrebbe farelet instance: any = this.constructor; console.log(instance.name);
Subash

7
@Subash un modo terser per evitare di proiettare a anyèconsole.log(instance.constructor['name']);
Nick Strupat

1
@Subash In alternativa, è possibile anche creare una dichiarazione di tipo: interface Function { name: string; }- ciò estenderà la definizione "nativa".
John Weisz,

1
MyClass.namenon funzionerà bene se stai minimizzando il tuo codice. Perché minimizzerà il nome della classe.
AngryHacker

28

So di essere in ritardo alla festa, ma trovo che anche questo funzioni.

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

In alternativa ...

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

Il codice precedente ottiene l'intero codice del costruttore come una stringa e applica una regex per ottenere tutte le "parole". La prima parola dovrebbe essere "funzione" e la seconda parola dovrebbe essere il nome della classe.

Spero che questo ti aiuti.


4
Scusa, certo. Di solito, usi la minificazione, la bruttezza e altri sistemi di post elaborazione. Quindi sul server di produzione il nome della tua classe non sarà lo stesso. E il tuo codice non funzionerà. Non ho trovato un'ottima soluzione per ottenere il nome della classe. Il modo più adatto è definire una variabile statica con il nome della tua classe.
Dima Kurilo,

23

La mia soluzione non era quella di fare affidamento sul nome della classe. object.constructor.name funziona in teoria. Ma se stai usando TypeScript in qualcosa come Ionic, non appena andrai in produzione andrà in fiamme perché la modalità di produzione di Ionic minimizza il codice Javascript. Quindi le classi prendono il nome di cose come "a" ed "e".

Quello che ho finito per fare è stato avere una classe typeName in tutti i miei oggetti a cui il costruttore assegna il nome della classe. Così:

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

constructor() {
typeName = "Person";
}

Sì, non era quello che era stato chiesto, davvero. Ma usare il nome constructor.name su qualcosa che potrebbe potenzialmente essere minimizzato lungo la strada è solo per chiedere mal di testa.


19

Vedere questo domanda .

Poiché TypeScript è compilato in JavaScript, in fase di esecuzione si esegue JavaScript, quindi verranno applicate le stesse regole.


14

Devi prima trasmettere l'istanza a anyperché Functionla definizione del tipo non ha una nameproprietà.

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"

Aggiornare:

Con TypeScript 2.4 (e potenzialmente precedente) il codice può essere anche più pulito:

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
Ho provato su TypeScript 2.6.2 e visualizzo questo errore:Property 'name' does not exist on type 'Function'.
orad

(this as {}).constructor.nameo (this as object).constructor.nameè meglio di anyperché allora ottieni il completamento automatico :-)
Simon_Weaver

5

In Angular2 questo può aiutare a ottenere il nome dei componenti:

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

comp: any è necessario perché la compilazione TypeScript genererà errori poiché inizialmente Function non ha un nome di proprietà.


5
tuttavia questo non funzionerà se minimizzi / riduci il tuo codice
Admir Sabanovic il

per ottenere un 'nome' utilizzabile di un componente è meglio ottenere il tagName di element.nativeElement- Su una direttiva è possibile ottenere il nome del componente in questo modo @Optional() element: ElementRef<HTMLElement>e quindi utilizzare if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
Simon_Weaver

(e i nomi dei tag non vengono minimizzati)
Simon_Weaver

4

Il codice TypeScript completo

public getClassName() {
    var funcNameRegex = /function (.{1,})\(/;
    var results  = (funcNameRegex).exec(this["constructor"].toString());
    return (results && results.length > 1) ? results[1] : "";
}

4
Potresti avere dei problemi se minimizzi e ottimizzi il tuo codice dattiloscritto / javascript. Potrebbe cambiare i nomi delle funzioni e quindi il confronto dei nomi delle classi potrebbe essere sbagliato.
Antti

4
  • Ho dovuto aggiungere " prototipo. " Per l'uso: myClass.prototype.constructor.name.
  • Altrimenti con il seguente codice myClass.constructor.name:, ho avuto l'errore TypeScript:

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


0

Questa soluzione funziona dopo l'ugualizzazione della minificazione ma richiede di decorare le classi con metadati.

Usiamo la generazione di codice per decorare le nostre classi di entità con metadati in questo modo:

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

Quindi consumare con il seguente aiuto:

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 sai già quali tipi aspettarti (ad esempio, quando un metodo restituisce un tipo di unione ), puoi utilizzare le protezioni dei tipi.

Ad esempio, per i tipi primitivi è possibile utilizzare una protezione typeof :

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

Per tipi complessi puoi usare un'istanza di guard :

if (thing instanceof Array) {
  // Do stuff
}

Immagino sia perché la tua risposta non è correlata alla domanda. La domanda era di ottenere il nome della classe per non fare condizionale cose sul tipo di istanza.
Daniel Leiszen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.