Получить свойства класса

Есть ли способ получить имена свойств класса в TypeScript?

В этом примере я хотел бы "описать" класс A или любой класс и получить массив его свойств (возможно, только public?), Возможно ли это? Или я должен сначала создать объект?

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'] */ 

Ответ 1

Этот TypeScript код

class A {
    private a1;
    public a2;
}

компилируется этот код JavaScript

class A {
}

Это потому, что свойства в JavaScript начинаются только после того, как они имеют некоторое значение. Вы должны присвоить свойствам какое-то значение.

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

он компилируется в

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

Тем не менее, вы не можете получить свойства из простого класса (вы можете получить только методы из прототипа). Вы должны создать экземпляр. Затем вы получаете свойства, вызывая Object.getOwnPropertyNames().

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

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

Применяется к вашему примеру

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

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

Ответ 2

Некоторые ответы частично неверны, а некоторые факты в них также частично неверны.

Ответьте на свой вопрос: да! Вы можете.

В машинописи

class A {
    private a1;
    private a2;


}

Создает следующий код в Javascript:

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

как сказал @Erik_Cupal, вы можете просто сделать:

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

Но это еще не все. Что произойдет, если у вашего класса есть собственный конструктор? Вы должны сделать трюк с Typescript, потому что он не будет компилироваться. Вам необходимо назначить как угодно:

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

Общее решение будет:

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

Для лучшего понимания это будет ссылаться в зависимости от контекста.

Ответ 3

Просто для удовольствия

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

Обновление. Если вы используете настраиваемые конструкторы, эта функция будет разорвана.

Ответ 4

Другое решение. Вы можете просто перебирать ключи объекта следующим образом : Примечание: вы должны использовать экземпляр объекта с существующими свойствами:

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