使用Typescript获取类的属性

mbo*_*ouz 40 reflection typescript

有没有办法在TypeScript中获取类的属性名称:在示例中,我想"描述"类A或任何类并获取其属性的数组(可能只是公共的?),是否可能?或者我应该首先实例化对象?

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'] */ 
Run Code Online (Sandbox Code Playgroud)

Eri*_*pal 29

这个TypeScript代码

class A {
    private a1;
    public a2;
}
Run Code Online (Sandbox Code Playgroud)

编译为此JavaScript代码

class A {
}
Run Code Online (Sandbox Code Playgroud)

那是因为JavaScript中的属性只有在它们有一些价值后才开始提升.您必须为属性分配一些值.

class A {
    private a1 = "";
    public a2 = "";
}
Run Code Online (Sandbox Code Playgroud)

它编译成

class A {
    constructor() {
        this.a1 = "";
        this.a2 = "";
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,你无法从纯粹的类中获取属性(你只能从原型获得方法).您必须创建一个实例.然后通过调用获得属性Object.getOwnPropertyNames().

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

array[0] === "a1";
array[1] === "a2";
Run Code Online (Sandbox Code Playgroud)

适用于您的示例

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

let a = new A();
let x = Describer.describe(a);
Run Code Online (Sandbox Code Playgroud)

  • 令人烦恼的是我们要定义一个默认值...特别是在模型中这很容易被遗忘,这可能导致很难找到的错误行为:/ (3认同)

tit*_*sfx 17

有些答案是部分错误的,其中的一些事实也是部分错误的.

回答你的问题:是的!您可以.

在打字稿中

class A {
    private a1;
    private a2;


}
Run Code Online (Sandbox Code Playgroud)

在Javascript中生成以下代码:

var A = /** @class */ (function () {
    function A() {
    }
    return A;
}());
Run Code Online (Sandbox Code Playgroud)

正如@Erik_Cupal所说,你可以做到:

let a = new A();
let array = return Object.getOwnPropertyNames(a);
Run Code Online (Sandbox Code Playgroud)

但这还不完整.如果您的类有自定义构造函数会发生什么?你需要使用Typescript做一个技巧,因为它不会编译.你需要分配任何:

let className:any = A;
let a = new className();// the members will have value undefined
Run Code Online (Sandbox Code Playgroud)

一般解决方案是:

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
   }
}
Run Code Online (Sandbox Code Playgroud)

为了更好地理解,将取决于上下文.

  • 不错的黑客!当然,不适用于每个构造函数。想象一下这样的事情:`constructor(callback: {getValue: () =&gt; number}) { this.numberValue = callback.getValue(); }` (2认同)

joh*_*y 5 10

另一个解决方案,你可以像这样迭代对象键,你必须首先实例化对象:

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

  • 该对象必须存在且要填充属性,否则将无法记录属性. (13认同)
  • 除非我弄错了,提问者想在运行时获得类属性的列表,可能不考虑是否有该类的实例。我遇到了这个,试图做到这一点,如果我不先实例化一个实例,就没有任何成功。 (2认同)

mad*_*son 8

纯娱乐

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"]
Run Code Online (Sandbox Code Playgroud)

更新:如果您使用自定义构造函数,此功能将中断.

  • 您需要初始化属性,以生成构造函数代码. (2认同)

yu *_*ian 7

其他答案主要获取对象的所有名称,要获取属性的值,您可以使用yourObj[name],例如:

var propNames = Object.getOwnPropertyNames(yourObj);
propNames.forEach(
    function(propName) {
        console.log(
           'name: ' + propName 
        + ' value: ' + yourObj[propName]);
    }
);
Run Code Online (Sandbox Code Playgroud)