Dapatkan nama kelas objek saat runtime

271

Apakah mungkin untuk mendapatkan nama kelas / jenis objek saat runtime menggunakan TypeScript?

class MyClass{}

var instance = new MyClass();
console.log(instance.????); // Should output "MyClass"
Adam Mills
sumber
3
Lihat di sini . Saat runtime Anda menjalankan JavaScript.
Matt Burland
1
Bagaimana Anda mendapatkan nama konstruktor dalam file TypeScript? Anda tidak dapat melakukan this.constructor.name dalam metode TypeScript (dalam file .ts).
sheldon_cooper

Jawaban:

462

Jawaban sederhana:

class MyClass {}

const instance = new MyClass();

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

Namun: berhati-hatilah bahwa nama itu kemungkinan akan berbeda ketika menggunakan kode yang diperkecil.

Mikael Couzic
sumber
14
Sayangnya MyClass.name adalah fitur ES6 karenanya tidak berfungsi di IE11.
perempuan
9
naskah akan membuat kesalahan pada ini. harus dilakukanlet instance: any = this.constructor; console.log(instance.name);
Subash
7
@ Subash cara terser untuk menghindari casting anyadalahconsole.log(instance.constructor['name']);
Nick Strupat
1
@ Subash Anda juga bisa membuat deklarasi tipe: interface Function { name: string; }- ini akan memperluas definisi "asli".
John Weisz
1
MyClass.nametidak akan berfungsi dengan baik jika Anda mengecilkan kode Anda. Karena itu akan mengecilkan nama kelas.
AngryHacker
28

Aku tahu aku terlambat ke pesta, tapi ternyata ini juga berhasil.

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

Kalau tidak...

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

Kode di atas mendapatkan seluruh kode konstruktor sebagai string dan menerapkan regex untuk mendapatkan semua 'kata'. Kata pertama harus 'berfungsi' dan kata kedua harus menjadi nama kelas.

Semoga ini membantu.


sumber
4
Maaf ya Biasanya, Anda menggunakan minifikasi, jelek dan sistem pemrosesan pos lainnya. Jadi pada server produksi nama kelas Anda tidak akan sama. Dan kode Anda tidak akan berfungsi. Saya tidak menemukan solusi yang bagus untuk mendapatkan nama kelas. Cara yang paling cocok adalah mendefinisikan variabel statis dengan nama kelas Anda.
Dima Kurilo
23

Solusi saya adalah tidak bergantung pada nama kelas. object.constructor.name bekerja secara teori. Tetapi jika Anda menggunakan TypeScript dalam sesuatu seperti Ionic, segera setelah Anda pergi ke produksi itu akan terbakar karena mode produksi Ionic mengecilkan kode Javascript. Jadi kelas diberi nama hal-hal seperti "a" dan "e."

Apa yang saya akhirnya lakukan adalah memiliki kelas typeName di semua objek saya bahwa konstruktor menetapkan nama kelas. Begitu:

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

constructor() {
typeName = "Person";
}

Ya, bukan itu yang ditanyakan, sungguh. Tetapi menggunakan constructor.name pada sesuatu yang mungkin berpotensi diperkecil di jalan hanya memohon sakit kepala.

SonOfALink
sumber
19

Lihat pertanyaan ini .

Karena TypeScript dikompilasi ke JavaScript, saat runtime Anda menjalankan JavaScript, jadi aturan yang sama akan berlaku.

Matt Burland
sumber
14

Anda harus terlebih dahulu melemparkan contoh ke anykarena Functiondefinisi tipe tidak memiliki nameproperti.

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"

Memperbarui:

Dengan TypeScript 2.4 (dan berpotensi lebih awal) kode dapat lebih bersih:

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
sumber
2
Mencoba pada TypeScript 2.6.2 dan saya mendapatkan kesalahan ini:Property 'name' does not exist on type 'Function'.
orad
(this as {}).constructor.nameatau (this as object).constructor.namelebih baik daripada anykarena Anda benar-benar mendapatkan autocomplete :-)
Simon_Weaver
5

Di Angular2 ini dapat membantu untuk mendapatkan nama komponen:

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

comp: any diperlukan karena kompilasi TypeScript akan mengeluarkan kesalahan karena Fungsi pada awalnya tidak memiliki nama properti.

Admir Sabanovic
sumber
5
namun ini tidak akan berfungsi jika Anda mengecilkan / uglifikasi kode Anda
Admir Sabanovic
untuk mendapatkan 'nama' komponen yang dapat digunakan, Anda lebih baik mendapatkan tagName dari element.nativeElement- Pada arahan Anda bisa mendapatkan nama komponen seperti ini @Optional() element: ElementRef<HTMLElement>dan kemudian menggunakan if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
Simon_Weaver
(dan nama tag tidak dikecualikan)
Simon_Weaver
4

Kode TypeScript lengkap

public getClassName() {
    var funcNameRegex = /function (.{1,})\(/;
    var results  = (funcNameRegex).exec(this["constructor"].toString());
    return (results && results.length > 1) ? results[1] : "";
}
Nati Krisi
sumber
4
Anda mungkin mendapatkan beberapa masalah jika Anda meminimalkan dan mengoptimalkan kode skrip / javascript Anda. Mungkin mengubah nama fungsi dan kemudian perbandingan nama kelas Anda mungkin salah.
Antti
4
  • Harus menambahkan " prototipe. " Penggunaan: myClass.prototype.constructor.name.
  • Kalau tidak, dengan kode berikut: myClass.constructor.nameSaya mengalami kesalahan TypeScript:

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

Flox
sumber
0

Solusi ini berfungsi setelah uglifikasi minifikasi tetapi membutuhkan dekorasi kelas dengan metadata.

Kami menggunakan pembuatan kode untuk menghias kelas Entitas kami dengan metadata seperti:

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

Kemudian konsumsilah dengan pembantu berikut:

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);
}
ttugate
sumber
-2

Jika Anda sudah tahu tipe apa yang diharapkan (misalnya, ketika suatu metode mengembalikan tipe gabungan ), maka Anda bisa menggunakan tipe penjaga.

Misalnya, untuk tipe primitif Anda dapat menggunakan typeof guard :

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

Untuk tipe kompleks Anda dapat menggunakan instanceof penjaga :

if (thing instanceof Array) {
  // Do stuff
}
Cocowalla
sumber
Saya kira ini karena jawaban Anda tidak terkait dengan pertanyaan. Pertanyaannya adalah untuk mendapatkan nama kelas agar tidak melakukan kondisional pada tipe instance.
Daniel Leiszen