Website-Suche

typescript - Eigenschaften einer Klasse abrufen


Gibt es eine Möglichkeit, die Eigenschaftsnamen einer Klasse in TypeScript zu erhalten?

In dem Beispiel möchte ich die Klasse A oder eine beliebige Klasse 'beschreiben' und ein Array ihrer Eigenschaften erhalten (vielleicht nur die public-Eigenschaften?), ist das möglich? Oder sollte ich das Objekt zuerst instanziieren?

class A {
    private a1;
    private a2;
    /** Getters and Setters */

}

class Describer<E> {
    toBeDescribed:E ;
    describe(): Array<string> {
        /**
         * Do something with 'toBeDescribed'                          
         */
        return ['a1', 'a2']; //<- Example
    }
}

let describer = new Describer<A>();
let x= describer.describe();
/** x should be ['a1', 'a2'] */ 

Antwort #1

Dieser TypeScript-Code

class A {
    private a1;
    public a2;
}

kompiliert zu diesem JavaScript-Code

class A {
}

Das liegt daran, dass Eigenschaften in JavaScript erst existieren, nachdem sie einen Wert haben. Sie müssen den Eigenschaften einen Wert zuweisen.

class A {
    private a1 = "";
    public a2 = "";
}

es wird kompiliert zu

class A {
    constructor() {
        this.a1 = "";
        this.a2 = "";
    }
}

Dennoch können Sie die Eigenschaften nicht aus einer bloßen Klasse erhalten (Sie können nur Methoden aus dem Prototyp erhalten). Sie müssen eine Instanz erstellen. Dann erhalten Sie die Eigenschaften, indem Sie Object.getOwnPropertyNames() aufrufen.

let a = new A();
let array = return Object.getOwnPropertyNames(a);

array[0] === "a1";
array[1] === "a2";

Auf Ihr Beispiel angewendet

class Describer {
    static describe(instance): Array<string> {
        return Object.getOwnPropertyNames(instance);
    }
}

let a = new A();
let x = Describer.describe(a);

Antwort #2

Einige Antworten sind teilweise falsch, und einige Fakten darin sind ebenfalls teilweise falsch.

Beantworte deine Frage: Ja! Du kannst.

In TypeScript

class A {
    private a1;
    private a2;


}

Generiert den folgenden Code in Javascript:

var A = /** @class */ (function () {
    function A() {
    }
    return A;
}());

wie @Erik_Cupal sagte, könntest du einfach Folgendes tun:

let a = new A();
let array = return Object.getOwnPropertyNames(a);

Aber das ist unvollständig. Was passiert, wenn Ihre Klasse einen benutzerdefinierten Konstruktor hat? Sie müssen einen Trick mit TypeScript anwenden, weil es sonst nicht kompiliert. Sie müssen es als any zuweisen:

let className:any = A;
let a = new className();// the members will have value undefined

Eine allgemeine Lösung wird sein:

class A {
    private a1;
    private a2;
    constructor(a1:number, a2:string){
        this.a1 = a1;
        this.a2 = a2;
    }
}

class Describer{

   describeClass( typeOfClass:any){
       let a = new typeOfClass();
       let array = Object.getOwnPropertyNames(a);
       return array;//you can apply any filter here
   }
}

Für ein besseres Verständnis wird dies je nach Kontext referenziert.

Antwort #3

Eine weitere Lösung, Sie können einfach über die Objekt-Schlüssel wie folgt iterieren, Hinweis: Sie müssen ein instanziiertes Objekt mit vorhandenen Eigenschaften verwenden:

printTypeNames<T>(obj: T) {
    const objectKeys = Object.keys(obj) as Array<keyof T>;
    for (let key of objectKeys)
    {
       console.log('key:' + key);
    }
}

Antwort #4

Nur zum Spaß

class A {
    private a1 = void 0;
    private a2 = void 0;
}

class B extends A {
    private a3 = void 0;
    private a4 = void 0;
}

class C extends B {
    private a5 = void 0;
    private a6 = void 0;
}

class Describer {
    private static FRegEx = new RegExp(/(?:this\.)(.+?(?= ))/g); 
    static describe(val: Function, parent = false): string[] {
        var result = [];
        if (parent) {
            var proto = Object.getPrototypeOf(val.prototype);
            if (proto) {
                result = result.concat(this.describe(proto.constructor, parent));
            } 
        }
        result = result.concat(val.toString().match(this.FRegEx) || []);
        return result;
    }
}

console.log(Describer.describe(A)); // ["this.a1", "this.a2"]
console.log(Describer.describe(B)); // ["this.a3", "this.a4"]
console.log(Describer.describe(C, true)); // ["this.a1", ..., "this.a6"]

Update: Wenn Sie benutzerdefinierte Konstruktoren verwenden, wird diese Funktionalität nicht mehr funktionieren.

Verwandte Artikel