Отримати ім’я класу об'єкта під час виконання


271

Чи можливо отримати ім’я класу / типу об’єкта під час виконання за допомогою TypeScript?

class MyClass{}

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

3
Дивіться тут . Під час виконання роботи ви запускаєте JavaScript.
— Метт Берланд

1
Як ви отримаєте ім'я конструктора у файлі TypeScript? Ви не можете цього зробити.constructor.name методом TypeScript (у .ts-файлі).
— sheldon_cooper

Відповіді:


461

Проста відповідь:

class MyClass {}

const instance = new MyClass();

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

Однак: будьте уважні, що ім'я, ймовірно, буде різним при використанні мінімізованого коду.


14
На жаль, MyClass.name є функцією ES6, тому він не працює в IE11.
— бегі

9
typecript викличе помилку на цьому. повинен зробитиlet instance: any = this.constructor; console.log(instance.name);
— Subash

7
@Subash в terser спосіб уникнути виливки на anyцеconsole.log(instance.constructor['name']);
— Нік Strupat

1
@Subash Ви також можете створити декларацію типу: interface Function { name: string; }- це розширить "рідне" визначення.
— Джон Вайс

1
MyClass.nameне буде добре, якщо ви мінімізуєте свій код. Тому що це мінімізує назву класу.
— AngryHacker

28

Я знаю, що я спізнююсь на вечірку, але знаходжу, що це теж працює.

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

Як варіант ...

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

Вищевказаний код отримує весь код конструктора як рядок і застосовує регулярний вираз, щоб отримати всі 'слова'. Перше слово має бути "функція", а друге - назва класу.

Сподіваюсь, це допомагає.


4
Вибачте, звичайно. Зазвичай ви використовуєте мінімізацію, некрасивість та інші системи післяобробки. Тож на виробничому сервері ім'я вашого класу не буде однаковим. І ваш код не буде працювати. Я не знайшов дійсно гарного рішення отримати назву класу. Найбільш підходящий спосіб - визначити статичну змінну з назвою вашого класу.
— Діма Курило

23

Моє рішення полягало не в тому, щоб покладатися на назву класу. object.constructor.name працює теоретично. Але якщо ви використовуєте TypeScript у чомусь схожому на Ionic, як тільки ви переходите до виробництва, він буде горіти полум'ям, оскільки режим виробництва Ionic мінімізує код Javascript. Тож на заняттях називають такі речі, як "a" та "e".

Що я в кінцевому підсумку робив - це мати клас typeName у всіх моїх об'єктах, яким конструктор присвоює ім'я класу. Так:

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

constructor() {
typeName = "Person";
}

Так, насправді не про це питали. Але використання constructor.name на чомусь, що потенційно може бути зменшене в дорозі, просто благає головного болю.


19

Дивіться це питання .

Оскільки TypeScript компілюється в JavaScript, під час виконання ви запускаєте JavaScript, тому застосовуватимуться ті самі правила.


14

Вам потрібно спочатку надати екземпляр anyтому Function, що визначення 'type' не має nameвластивості.

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"

Оновлення:

З TypeScript 2.4 (а можливо і раніше) код може бути ще чистішим:

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, і я отримую цю помилку:Property 'name' does not exist on type 'Function'.
— orad

(this as {}).constructor.nameабо (this as object).constructor.nameкраще, ніж anyтому, що тоді ви фактично отримуєте автозаповнення :-)
— Simon_Weaver

5

У Angular2 це може допомогти отримати ім'я компонентів:

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

comp: будь- яка потрібна, оскільки компіляція TypeScript видасть помилки, оскільки функція спочатку не має імені властивості.


5
однак це не вийде, якщо ви мінімізуєте /
— скасуєте

щоб отримати зручне "ім'я" компонента, вам краще отримати тегName of element.nativeElement- У директиві ви можете отримати ім'я компонента, як це, @Optional() element: ElementRef<HTMLElement>а потім використовувати if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
— Simon_Weaver

(і назви тегів не змінюються)
— Simon_Weaver

4

Повний код TypeScript

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

4
У вас можуть виникнути деякі проблеми, якщо ви мінімізуєте та оптимізуєте свій код друку / JavaScript. Це може змінити назви функцій, і тоді порівняння імен вашого класу може бути неправильним.
— Антті

4
  • Довелося додати « прототип. » Для використання: myClass.prototype.constructor.name.
  • Інакше зі наступним кодом: у myClass.constructor.nameмене виникла помилка TypeScript:

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


0

Це рішення працює після мінімізації мінімізації, але вимагає прикрасити класи метаданими.

Ми використовуємо генерацію коду для прикраси наших курсів Entity такими метаданими:

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

Потім споживайте наступного помічника:

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

Якщо ви вже знаєте, яких типів очікувати (наприклад, коли метод повертає тип з'єднання ), тоді ви можете використовувати типи захисту.

Наприклад, для примітивних типів можна використовувати захист typeof :

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

Для складних типів ви можете використовувати instanceof guard :

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

Я здогадуюсь, тому що ваша відповідь не пов'язана з питанням. Питання полягало в тому, щоб отримати назву класу не умовно робити речі за типом екземпляра.
— Даніель Лейцен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.