È 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"
È 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"
Risposte:
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.
let instance: any = this.constructor; console.log(instance.name);
anyèconsole.log(instance.constructor['name']);
interface Function { name: string; }- ciò estenderà la definizione "nativa".
MyClass.namenon funzionerà bene se stai minimizzando il tuo codice. Perché minimizzerà il nome della classe.
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.
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.
Vedere questo domanda .
Poiché TypeScript è compilato in JavaScript, in fase di esecuzione si esegue JavaScript, quindi verranno applicate le stesse regole.
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"
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"
Property 'name' does not exist on type 'Function'.
(this as {}).constructor.nameo (this as object).constructor.nameè meglio di anyperché allora ottieni il completamento automatico :-)
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à.
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; }
Il codice TypeScript completo
public getClassName() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(this["constructor"].toString());
return (results && results.length > 1) ? results[1] : "";
}
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);
}
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
}