在运行时获取对象的类名

是否有可能在运行时使用TypeScript获得对象的类/类型名?

class MyClass{}


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

请看这个问题

因为TypeScript被编译成JavaScript,所以在运行时你运行的是JavaScript,所以同样的规则也适用。

完整的TypeScript代码

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

我知道我迟到了,但我发现这个方法也很有效。

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

或者……

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

上面的代码以字符串的形式获取整个构造函数代码,并应用正则表达式来获取所有的“words”。第一个单词应该是“function”,第二个单词应该是类的名称。

希望这能有所帮助。

简单的回答:

class MyClass {}


const instance = new MyClass();


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

但是,要注意,在使用简化代码时,名称可能会有所不同。

在Angular2中,这可以帮助获取组件名称:

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

薪酬:任何是必需的,因为TypeScript编译器会报错,因为Function最初没有属性名。

首先需要将实例强制转换为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"

我的解决方案是不依赖类名。Object.constructor.name在理论上是可行的。但如果你在Ionic这样的平台上使用TypeScript,一旦你进入生产模式,它就会陷入困境,因为Ionic的生产模式减少了Javascript代码。所以类被命名为“a”和“e”。

我最后做的是在我的所有对象中都有一个typeName类,构造函数将类名赋给它。所以:

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


constructor() {
typeName = "Person";
}

是的,这不是问的,真的。但是将constructor.name用于将来可能会被最小化的东西上是在自找麻烦。

  • 不得不加上“。< em >原型。< / em >"使用:myClass.prototype.constructor.name
  • 否则使用以下代码: myClass.constructor.name,我有TypeScript错误:

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

如果你已经知道预期的类型(例如,当一个方法返回联合类型时),那么你可以使用类型保护。

例如,对于基元类型,可以使用typeof警卫:

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

对于复杂类型,可以使用instanceof警卫:

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

解决方案使用装饰器,缩小/丑陋

我们使用代码生成用元数据来装饰我们的实体类,如下所示:

@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);
}

额外信息:

  • 你可能需要安装reflect-metadata
  • reflect-metadata是由TypeScript成员为提议的ES7反射API编写的填充
  • JS中装饰器的建议可以是在这里跟踪