Получить имя класса объекта во время выполнения


273

Можно ли получить имя класса / типа объекта во время выполнения, используя TypeScript?

class MyClass{}

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

3
Смотрите здесь . Во время выполнения вы используете JavaScript.
Мэтт Берланд

1
Как вы получаете имя конструктора в файле TypeScript? Вы не можете сделать this.constructor.name в методе TypeScript (в файле .ts).
sheldon_cooper

Ответы:


464

Простой ответ:

class MyClass {}

const instance = new MyClass();

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

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


14
К сожалению, MyClass.name является функцией ES6, поэтому он не работает в IE11.
begie

9
машинопись выдаст ошибку на этом. должен сделатьlet instance: any = this.constructor; console.log(instance.name);
Субаш

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. Таким образом, классы именуются такими вещами, как «а» и «е».

В результате я получил класс typeName во всех моих объектах, которым конструктор назначает имя класса. Так:

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

constructor() {
typeName = "Person";
}

Да, это было не то, что спросили, правда. Но использование constructor.name для чего-то, что потенциально может быть сведено к минимуму, просто умоляет о головной боли.


19

Смотрите этот вопрос .

Поскольку TypeScript скомпилирован в JavaScript, во время выполнения вы запускаете JavaScript, поэтому будут применяться те же правила.


14

Сначала необходимо привести экземпляр к, anyтак Functionкак определение типа не имеет 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: any необходим, потому что компиляция TypeScript выдаст ошибки, так как функция изначально не имеет имени свойства.


5
однако это не будет работать, если вы уменьшите / уменьшите свой код
Admir Sabanovic

чтобы получить пригодное для использования «имя» компонента, вам лучше получить tagName: 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 guard :

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.