Çalışma zamanında bir nesnenin sınıf adını alma


271

TypeScript kullanarak çalışma zamanında bir nesnenin sınıf / tür adını almak mümkün müdür?

class MyClass{}

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

3
Buraya bakın . Çalışma zamanında JavaScript çalıştırıyorsunuz.
Matt Burland

1
Yapıcı adını TypeScript dosyasında nasıl alırsınız? This.constructor.name dosyasını bir TypeScript yönteminde (.ts dosyasında) yapamazsınız.
sheldon_cooper

Yanıtlar:


461

Basit cevap:

class MyClass {}

const instance = new MyClass();

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

Ancak: küçültülmüş kodu kullanırken adın muhtemelen farklı olacağını unutmayın.


14
Ne yazık ki MyClass.name bir ES6 özelliğidir, bu nedenle IE11'de çalışmaz.
begie

9
typescript bu konuda hata verecektir. yapmalılet instance: any = this.constructor; console.log(instance.name);
Subash

7
@ Döküm önlemek için ters bir yol anyolduğunuconsole.log(instance.constructor['name']);
Nick Strupat

1
@Subash Bunun yerine bir tür bildirimi de oluşturabilirsiniz: interface Function { name: string; }- bu, "yerel" tanımı genişletir.
John Weisz

1
MyClass.namekodunuzu küçültüyorsanız iyi çalışmaz. Çünkü sınıfın adını minimize edecektir.
AngryHacker

28

Partiye geç kaldığımı biliyorum, ama bunun da işe yaradığını görüyorum.

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

Alternatif ...

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

Yukarıdaki kod, tüm yapıcı kodunu bir dize olarak alır ve tüm 'kelimeleri' almak için bir normal ifade uygular. İlk kelime 'işlev', ikinci kelime sınıfın adı olmalıdır.

Bu yardımcı olur umarım.


4
Üzgünüm, tabi. Genellikle, küçültme, çirkinleştirme ve diğer işlem sonrası sistemleri kullanırsınız. Yani üretim sunucusunda sınıf adınız aynı olmaz. Ve kodunuz çalışmaz. Sınıf adı almak için gerçekten iyi bir çözüm bulamadım. En uygun yol, sınıf adınızla statik bir değişken tanımlamaktır.
Dima Kurilo

23

Benim çözümüm sınıf ismine güvenmek değildi. object.constructor.name teoride çalışır. Ancak TypeScript'i Ionic gibi bir şeyde kullanıyorsanız, üretime girer girmez alevler içinde yükselir, çünkü Ionic'in üretim modu Javascript kodunu en aza indirir. Böylece sınıflara "a" ve "e" gibi adlar verilir.

Yaptığım şey, yapıcıya sınıf adını atadığı tüm nesnelerimde bir typeName sınıfına sahip olmaktı. Yani:

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

constructor() {
typeName = "Person";
}

Evet, gerçekten sorulan şey bu değildi. Ancak constructor.name dosyasını potansiyel olarak küçültülebilecek bir şeyde kullanmak sadece baş ağrısı için yalvarıyor.


19

Bu soruya bakın .

TypeScript JavaScript'e derlendiğinden, çalışma zamanında JavaScript çalıştırıyorsunuz, bu nedenle aynı kurallar geçerli olacaktır.


14

Örneği türüne atamanız gerekir anyçünkü Function's tür tanımının bir nameözelliği yoktur.

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"

Güncelleme:

TypeScript 2.4 (ve muhtemelen daha önce) ile kod daha da temiz olabilir:

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
TypeScript 2.6.2 üzerinde denedim ve şu hatayı alıyorum:Property 'name' does not exist on type 'Function'.
orad

(this as {}).constructor.nameya (this as object).constructor.nameda daha iyidir anyçünkü o zaman aslında otomatik tamamlama alırsınız :-)
Simon_Weaver

5

Angular2'de bu bileşen adının alınmasına yardımcı olabilir:

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

comp: Herhangi biri gereklidir çünkü TypeScript derlemesi İşlev başlangıçta özellik adına sahip olmadığından hatalar verir.


5
ancak, kodunuzu küçültme / büyütme işleminde çalışmaz
Admir Sabanovic

bir bileşenin kullanılabilir bir 'adını' almak için tagName'i almaktan daha iyidir element.nativeElement- Direktifte bileşenin adını bu şekilde alabilir @Optional() element: ElementRef<HTMLElement>ve kullanabilirsiniz if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
Simon_Weaver

(ve etiket adları küçültülmez)
Simon_Weaver

4

Tam TypeScript kodu

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

4
Yazı tipi / javascript kodunuzu simge durumuna küçültüp optimize ederseniz bazı sorunlar yaşayabilirsiniz. İşlev adlarını değiştirebilir ve ardından sınıf adı karşılaştırmanız yanlış olabilir.
Antti

4
  • "Eklemek zorunda kaldı . Prototip kullanımına": myClass.prototype.constructor.name.
  • Aksi takdirde aşağıdaki kodla: myClass.constructor.nameTypeScript hatası aldım:

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


0

Bu çözüm, küçültme uglification sonra çalışır, ancak sınıfları meta veri ile dekore gerektirir.

Entity sınıflarımızı meta verilerle süslemek için kod oluşturma yöntemini kullanırız:

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

Ardından aşağıdaki yardımcıyla tüketin:

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

Hangi türlerin bekleneceğini zaten biliyorsanız (örneğin, bir yöntem bir birleşim türü döndürdüğünde ), tür korumaları kullanabilirsiniz.

Örneğin, ilkel tipler için bir tip guard kullanabilirsiniz :

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

Karmaşık tipler için bir koruma örneği kullanabilirsiniz :

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

Sanırım cevabınız soru ile ilgili değil. Soru, sınıf adını koşullu olarak örnek türünde şeyler yapmamasını sağlamaktı.
Daniel Leiszen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.