実行時にオブジェクトのクラス名を取得する


271

TypeScriptを使用して実行時にオブジェクトのクラス/タイプ名を取得することは可能ですか?

class MyClass{}

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

3
こちらをご覧ください。実行時にJavaScriptを実行しています。
— Matt Burland

1
TypeScriptファイルでコンストラクタ名をどのように取得しますか?TypeScriptメソッド(.tsファイル内)ではthis.constructor.nameを実行できません。
— 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では機能しません。
— 2016年

9
typescriptはこれでエラーをスローします。する必要があります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; }これにより、「ネイティブ」定義が拡張されます。
— John Weisz 2016

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];

上記のコードは、コンストラクターコード全体を文字列として取得し、正規表現を適用してすべての「単語」を取得します。最初の単語は「関数」でなければならず、2番目の単語はクラスの名前でなければなりません。

お役に立てれば。


4
すみません。通常、縮小化、醜化およびその他の後処理システムを使用します。したがって、本番サーバーではクラス名は同じにはなりません。そして、あなたのコードは機能しません。クラス名を取得するための本当に良い解決策が見つかりませんでした。最も適切な方法は、クラス名で静的変数を定義することです。
— Dima Kurilo 2016年

23

私の解決策は、クラス名に依存しないことでした。object.constructor.nameは理論的に機能します。しかし、IonicのようなものでTypeScriptを使用している場合、本番環境に入るとすぐに、Ionicの本番モードはJavascriptコードを最小化するため、炎上します。したがって、クラスには「a」や「e」などの名前が付けられます。

私がやったことは、コンストラクターがクラス名を割り当てるすべてのオブジェクトにtypeNameクラスを含めることでした。そう:

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

constructor() {
typeName = "Person";
}

はい、そうではありませんでした。しかし、将来的に縮小される可能性のあるものにコンストラクター。名前を使用すると、頭痛の種になるだけです。


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
活字体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;
    }

TypeScriptコンパイルは、最初はFunctionにプロパティ名がないため、エラーを発行するため、comp:anyが必要です。


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
typescript / javascriptコードを最小化して最適化すると、いくつかの問題が発生する可能性があります。関数名が変更され、クラス名の比較が間違っている可能性があります。
— Antti

4
  • 使用する「。prototype 。」を追加する必要がありました:myClass.prototype.constructor.name。
  • それ以外の場合、次のコード: myClass.constructor.name、TypeScriptエラーが発生しました:

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


0

このソリューションは、縮小化後に機能しますが、メタデータでクラスを装飾する必要があります。

コード生成を使用して、エンティティクラスを次のようなメタデータで装飾します。

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

あなたの答えが質問に関係していないからだと思います。問題は、クラス名をインスタンスタイプで条件付きで実行しないようにすることでした。
— Daniel Leiszen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.