Nhận tên lớp của đối tượng trong thời gian chạy


271

Có thể lấy tên lớp / loại của đối tượng trong thời gian chạy bằng TypeScript không?

class MyClass{}

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

3
Xem tại đây . Trong thời gian chạy, bạn đang chạy JavaScript.
Matt Burland

1
Làm thế nào để bạn có được tên constructor trong tệp TypeScript? Bạn không thể thực hiện this.constructor.name trong phương thức TypeScript (trong tệp .ts).
sheldon_cooper

Câu trả lời:


458

Câu trả lời đơn giản:

class MyClass {}

const instance = new MyClass();

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

Tuy nhiên: hãy cẩn thận rằng tên có thể sẽ khác khi sử dụng mã được rút gọn.


14
Thật không may, MyClass.name là một tính năng ES6 do đó nó không hoạt động trong IE11.
begie

9
bản đánh máy sẽ ném lỗi về điều này. nên làmlet instance: any = this.constructor; console.log(instance.name);
Subash

7
@Subash một cách khó khăn hơn để tránh truyền vào anyconsole.log(instance.constructor['name']);
Nick Strupat

1
@Subash Bạn cũng có thể tạo một khai báo kiểu thay thế: interface Function { name: string; }- điều này sẽ mở rộng định nghĩa "gốc".
John Weisz

1
MyClass.namesẽ không hoạt động tốt nếu bạn đang thu nhỏ mã của mình. Bởi vì nó sẽ thu nhỏ tên của lớp.
AngryHacker

28

Tôi biết tôi đến bữa tiệc muộn, nhưng tôi thấy rằng điều này cũng hoạt động.

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

Hoặc ...

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

Đoạn mã trên lấy toàn bộ mã xây dựng thành một chuỗi và áp dụng biểu thức chính quy để nhận tất cả 'từ'. Từ đầu tiên phải là 'hàm' và từ thứ hai phải là tên của lớp.

Hi vọng điêu nay co ich.


4
Xin lỗi, chắc chắn rồi. Thông thường, bạn sử dụng minifying, uglyfication và các hệ thống xử lý bài khác. Vì vậy, trên máy chủ sản xuất, tên lớp của bạn sẽ không giống nhau. Và mã của bạn sẽ không hoạt động. Tôi đã không tìm thấy giải pháp thực sự tốt để có được tên lớp. Cách phù hợp nhất là định nghĩa một biến tĩnh với tên lớp của bạn.
Dima Kurilo

23

Giải pháp của tôi là không dựa vào tên lớp. object.constructor.name hoạt động trên lý thuyết. Nhưng nếu bạn đang sử dụng TypeScript trong một cái gì đó như Ionic, ngay khi bạn đi vào sản xuất, nó sẽ bùng cháy vì chế độ sản xuất của Ionic làm giảm mã Javascript. Vì vậy, các lớp được đặt tên những thứ như "a" và "e."

Điều cuối cùng tôi đã làm là có một lớp typeName trong tất cả các đối tượng của tôi mà hàm tạo gán tên lớp cho. Vì thế:

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

constructor() {
typeName = "Person";
}

Vâng, đó không phải là những gì được yêu cầu, thực sự. Nhưng việc sử dụng constructor.name trên một cái gì đó có khả năng bị thu nhỏ xuống đường chỉ là một sự đau đầu.


19

Xem câu hỏi này .

Vì TypeScript được biên dịch thành JavaScript, nên trong thời gian chạy, bạn đang chạy JavaScript, do đó, các quy tắc tương tự sẽ được áp dụng.


14

Trước tiên, bạn cần truyền ví dụ sang anyFunctionđịnh nghĩa loại không có thuộc nametính.

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"

Cập nhật:

Với TypeScript 2.4 (và có khả năng sớm hơn), mã có thể sạch hơn:

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
Đã thử trên TypeScript 2.6.2 và tôi gặp lỗi này:Property 'name' does not exist on type 'Function'.
orad

(this as {}).constructor.namehoặc (this as object).constructor.nametốt hơn là anyvì sau đó bạn thực sự nhận được tự động hoàn thành :-)
Simon_Weaver

4

Mã TypeScript đầy đủ

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

4
Bạn có thể gặp một số vấn đề nếu bạn giảm thiểu và tối ưu hóa mã bản thảo / javascript của mình. Nó có thể thay đổi tên hàm và sau đó so sánh tên lớp của bạn có thể sai.
Antti

4

Trong Angular2, điều này có thể giúp lấy tên thành phần:

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

comp: bất kỳ là cần thiết vì trình biên dịch TypeScript sẽ phát sinh lỗi vì Hàm ban đầu không có tên thuộc tính.


5
tuy nhiên điều này sẽ không hoạt động nếu bạn thu nhỏ / làm xấu mã của bạn
Admir Sabanovic

để có được 'tên' có thể sử dụng của một thành phần, bạn nên lấy tagName của element.nativeElement- Theo chỉ thị, bạn có thể lấy tên của thành phần như thế này @Optional() element: ElementRef<HTMLElement>và sau đó sử dụng if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
Simon_Weaver

(và tên thẻ không được rút gọn)
Simon_Weaver

4
  • Phải thêm ". Nguyên mẫu. " Để sử dụng : myClass.prototype.constructor.name.
  • Mặt khác với đoạn mã sau : myClass.constructor.name, tôi đã gặp lỗi TypeScript:

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


0

Giải pháp này hoạt động sau khi thu nhỏ hóa nhưng yêu cầu trang trí các lớp bằng siêu dữ liệu.

Chúng tôi sử dụng việc tạo mã để trang trí các lớp Thực thể của mình bằng siêu dữ liệu như vậy:

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

Sau đó tiêu thụ với người trợ giúp sau:

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

Nếu bạn đã biết loại nào sẽ xảy ra (ví dụ: khi một phương thức trả về loại kết hợp ), thì bạn có thể sử dụng các loại bảo vệ.

Ví dụ: đối với các kiểu nguyên thủy, bạn có thể sử dụng bộ bảo vệ kiểu :

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

Đối với các loại phức tạp, bạn có thể sử dụng một bảo vệ thể hiện :

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

Tôi đoán nó bởi vì câu trả lời của bạn không liên quan đến câu hỏi. Câu hỏi là để có được tên lớp không có điều kiện Làm công cụ trên loại cá thể.
Daniel Leiszen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.