Is it possible to get an object's class/type name at runtime using TypeScript?
class MyClass{}
var instance = new MyClass();
console.log(instance.????); // Should output "MyClass"
Is it possible to get an object's class/type name at runtime using TypeScript?
class MyClass{}
var instance = new MyClass();
console.log(instance.????); // Should output "MyClass"
class MyClass {}
const instance = new MyClass();
console.log(instance.constructor.name); // MyClass
console.log(MyClass.name); // MyClass
However: beware that the name will likely be different when using minified code.
let instance: any = this.constructor; console.log(instance.name);
–
Orchestra any
is console.log(instance.constructor['name']);
–
Mammillate interface Function { name: string; }
-- this will extend the "native" definition. –
Toccaratoccata constructor.name
same with @NickStrupat suggested solution –
Select this.constructor.name
will give you the child class name while the other one will obviously stay fixed to the parent. –
Cogitate MyClass.name
won't work well if you are minifying your code. Because it will minify the name of the class. –
Giulia My solution was not to rely on the class name. object.constructor.name works in theory. But if you're using TypeScript in something like Ionic, as soon as you go to production it's going to go up in flames because Ionic's production mode minifies the Javascript code. So the classes get named things like "a" and "e."
What I ended up doing was having a typeName class in all my objects that the constructor assigns the class name to. So:
export class Person {
id: number;
name: string;
typeName: string;
constructor() {
typeName = "Person";
}
Yes that wasn't what was asked, really. But using the constructor.name on something that might potentially get minified down the road is just begging for a headache.
let instance=new Person (); (instance.constructor.name==Person.name)
both names should get minified to the same thing. –
Ase a
, b
, c
, etc. so you shouldn't rely on this. –
Swor I know I'm late to the party, but I find that this works too.
var constructorString: string = this.constructor.toString();
var className: string = constructorString.match(/\w+/g)[1];
Alternatively...
var className: string = this.constructor.toString().match(/\w+/g)[1];
The above code gets the entire constructor code as a string and applies a regex to get all 'words'. The first word should be 'function' and the second word should be the name of the class.
Hope this helps.
You need to first cast the instance to any
because Function
's type definition does not have a name
property.
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"
With TypeScript 2.4 (and potentially earlier) the code can be even cleaner:
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"
Property 'name' does not exist on type 'Function'.
–
Throughway (this as {}).constructor.name
or (this as object).constructor.name
is better than any
because then you actually get autocomplete :-) –
Nee Solution using Decorators that survives minification/uglification
We use code generation to decorate our Entity classes with metadata like so:
@name('Customer')
export class Customer {
public custId: string;
public name: string;
}
Then consume with the following helper:
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);
}
Extra info:
reflect-metadata
reflect-metadata
is pollyfill written by members ot TypeScript for the proposed ES7 Reflection APISee this question.
Since TypeScript is compiled to JavaScript, at runtime you are running JavaScript, so the same rules will apply.
In Angular2, this can help to get components name:
getName() {
let comp:any = this.constructor;
return comp.name;
}
comp:any is needed because TypeScript compiler will issue errors since Function initially does not have property name.
element.nativeElement
- On a directive you can get the component's name like this @Optional() element: ElementRef<HTMLElement>
and then use if (element != null && element.nativeElement.tagName.startsWith('APP-')) { this.name = element.nativeElement.tagName; }
–
Nee myClass.prototype.constructor.name
.myClass.constructor.name
, I had the TypeScript error : error TS2339: Property 'name' does not exist on type 'Function'
.
The full TypeScript code
public getClassName() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(this["constructor"].toString());
return (results && results.length > 1) ? results[1] : "";
}
I don't know since when this is possible, but right now it is:
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
}
class Lion extends Animal {
keeper: ZooKeeper;
}
function createInstance<A extends Animal>(c: new () => A): A {
console.log(c.name) //this will give the class name
return new c();
}
createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;
Credits to this tutorial
If you already know what types to expect (for example, when a method returns a union type), then you can use type guards.
For example, for primitive types you can use a typeof guard:
if (typeof thing === "number") {
// Do stuff
}
For complex types you can use an instanceof guard:
if (thing instanceof Array) {
// Do stuff
}
© 2022 - 2024 — McMap. All rights reserved.