Typescript 获取类的属性

Typescript 获取类的属性,typescript,reflection,Typescript,Reflection,有没有办法在TypeScript中获取类的属性名 在本例中,我想“描述”类A或任何类,并获取其属性数组(可能只有public属性?),是否可能?或者我应该先实例化对象吗 class A { private a1; private a2; /** Getters and Setters */ } class Describer<E> { toBeDescribed:E ; describe(): Array<string> {

有没有办法在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'] */ 
A类{
私人a1;
私人a2;
/**接球手和接球手*/
}
类描述符{
描述:E;
descripe():数组{
/**
*用“TobeDescripted”做点什么
*/
返回['a1','a2'];//此类型脚本代码

class A {
    private a1;
    public a2;
}
class A {
}
编译为该JavaScript代码

class A {
    private a1;
    public a2;
}
class A {
}
这是因为JavaScript中的属性只有在具有某些值后才会开始extisting。您必须为属性分配一些值

class A {
    private a1 = "";
    public a2 = "";
}
它编译为

class A {
    constructor() {
        this.a1 = "";
        this.a2 = "";
    }
}
但是,您不能仅从类中获取属性(只能从原型中获取方法)。您必须创建一个实例。然后通过调用
对象.getOwnPropertyNames()
来获取属性

适用于你的例子
类描述符{
静态描述(实例):数组{
返回Object.getOwnPropertyNames(实例);
}
}
设a=新a();
设x=描述者。描述(a);
只是为了好玩

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

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

另一种解决方案,您可以像这样迭代对象键, 注意:必须使用具有现有属性的实例化对象

printTypeNames<T>(obj: T) {
    const objectKeys = Object.keys(obj) as Array<keyof T>;
    for (let key of objectKeys)
    {
       console.log('key:' + key);
    }
}
printTypeNames(obj:T){
const objectKeys=Object.keys(obj)作为数组;
for(对象键中的let键)
{
console.log('key:'+key);
}
}

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

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

在Typescript中

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

为了更好地理解,此将根据上下文引用。

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

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

我目前正在为Typescript开发一个类似Linq的库,并希望在Typescript/Javascript中实现类似C#的GetProperties。我使用Typescript和泛型的次数越多,我就越清楚地了解到,通常必须有一个具有初始化属性的实例化对象,才能在runtim上获得任何有用的信息但是,只要从构造函数对象或对象数组中检索信息,并灵活处理,就好了

这就是我现在的结局

首先,我定义了数组原型方法(“扩展方法”适用于C#开发人员)

在这里你可以看到两个测试茉莉花的规格

class Hero {
  name: string;
  gender: string;
  age: number;
  constructor(name: string = "", gender: string = "", age: number = 0) {
    this.name = name;
    this.gender = gender;
    this.age = age;
  }
}

class HeroWithAbility extends Hero {
  ability: string;
  constructor(ability: string = "") {
    super();
    this.ability = ability;
  }
}

describe('Array Extensions tests for TsExtensions Linq esque library', () => {

  it('can retrieve props for a class items of an array', () => {
    let heroes: Hero[] = [<Hero>{ name: "Han Solo", age: 44, gender: "M" }, <Hero>{ name: "Leia", age: 29, gender: "F" }, <Hero>{ name: "Luke", age: 24, gender: "M" }, <Hero>{ name: "Lando", age: 47, gender: "M" }];
    let foundProps = heroes.GetProperties(Hero, false);
    //debugger
    let expectedArrayOfProps = ["name", "age", "gender"];
    expect(foundProps).toEqual(expectedArrayOfProps);
    expect(heroes.GetProperties(Hero, true)).toEqual(["age", "gender", "name"]);
  });

  it('can retrieve props for a class only knowing its function', () => {
    let heroes: Hero[] = [];
    let foundProps = heroes.GetProperties(Hero, false);
    let expectedArrayOfProps = ["this.name", "this.gender", "this.age"];
    expect(foundProps).toEqual(expectedArrayOfProps);
    let foundPropsThroughClassFunction = heroes.GetProperties(Hero, true);
    //debugger
    expect(foundPropsThroughClassFunction.SequenceEqual(["this.age", "this.gender", "this.name"])).toBe(true);
  });
职业英雄{
名称:字符串;
性别:弦;
年龄:人数;
构造函数(名称:string=“”,性别:string=“”,年龄:number=0){
this.name=名称;
这个。性别=性别;
这个。年龄=年龄;
}
}
类HeroWithAbility扩展了Hero{
能力:字符串;
构造函数(能力:string=”“){
超级();
能力=能力;
}
}
description('TsExtensions Linq-esque库的阵列扩展测试',()=>{
它('可以为数组的类项目检索道具',()=>{
让英雄:英雄[]=[{姓名:“汉·索洛”,年龄:44岁,性别:“M”},{姓名:“莱娅”,年龄:29岁,性别:“F”},{姓名:“卢克”,年龄:24岁,性别:“M”},{姓名:“兰多”,年龄:47岁,性别:“M”};
让foundProps=heros.GetProperties(Hero,false);
//调试器
让expectedArrayOfProps=[“姓名”、“年龄”、“性别”];
expect(foundProps)。toEqual(expectedArrayOfProps);
expect(heromes.GetProperties(Hero,true)).toEqual([“年龄”、“性别”、“姓名]);
});
它('只能为知道其函数的类检索道具',()=>{
让英雄:英雄[]=[];
让foundProps=heros.GetProperties(Hero,false);
让expectedArrayOfProps=[“this.name”,“this.gender”,“this.age”];
expect(foundProps)。toEqual(expectedArrayOfProps);
让foundPropsThroughClassFunction=heros.GetProperties(Hero,true);
//调试器
expect(foundPropsThroughClassFunction.SequenceEqual([“this.age”、“this.gender”、“this.name”])).toBe(true);
});
正如madreason所提到的,您必须初始化道具,以便仅从类函数本身获取任何信息,否则当Typescript代码转换为Javascript代码时,它就会被剥离

Typescript 3.7对于泛型非常好,但是来自C#和反射的背景,Typescript和泛型的一些基本部分仍然感觉有些松散和未完成的工作。就像我这里的代码一样,但至少我得到了我想要的信息——给定类或对象实例的属性名称列表

SequenceEqual是这种方法,顺便说一句:

    if (!Array.prototype.SequenceEqual) {
  Array.prototype.SequenceEqual = function <T>(compareArray: T): boolean {
    if (!Array.isArray(this) || !Array.isArray(compareArray) || this.length !== compareArray.length)
      return false;
    var arr1 = this.concat().sort();
    var arr2 = compareArray.concat().sort();
    for (var i = 0; i < arr1.length; i++) {
      if (arr1[i] !== arr2[i])
        return false;
    }
    return true;
  }
}
if(!Array.prototype.SequenceEqual){
Array.prototype.SequenceEqual=函数(comparararray:T):布尔值{
如果(!Array.isArray(this)| |!Array.isArray(comparararray)| | this.length!==comparararray.length)
返回false;
var arr1=this.concat().sort();
var arr2=compararray.concat().sort();
对于(变量i=0;i
使用这些

export class TableColumns<T> {
   constructor(private t: new () => T) {
        var fields: string[] = Object.keys(new t())

        console.log('fields', fields)
        console.log('t', t)

    }
}
js类

t class LogItem {
constructor() {
    this.id = 0;
    this.code = 0;
    this.source = '';
    this.title = '';
    this.deleted = false;
    this.checked = false;
  …

这里还有一个答案也符合作者的要求:

如果您使用插件和类的接口,您可以获得类的所有键

但如果您使用Angular或React,则在某些情况下,需要进行额外的配置(webpack和typescript)才能使其正常工作:<
    if (!Array.prototype.SequenceEqual) {
  Array.prototype.SequenceEqual = function <T>(compareArray: T): boolean {
    if (!Array.isArray(this) || !Array.isArray(compareArray) || this.length !== compareArray.length)
      return false;
    var arr1 = this.concat().sort();
    var arr2 = compareArray.concat().sort();
    for (var i = 0; i < arr1.length; i++) {
      if (arr1[i] !== arr2[i])
        return false;
    }
    return true;
  }
}
export class TableColumns<T> {
   constructor(private t: new () => T) {
        var fields: string[] = Object.keys(new t())

        console.log('fields', fields)
        console.log('t', t)

    }
}
columns_logs = new TableColumns<LogItem>(LogItem);
fields (12) ["id", "code", "source", "title", "deleted", "checked", "body", "json", "dt_insert", "dt_checked", "screenshot", "uid"]
t class LogItem {
constructor() {
    this.id = 0;
    this.code = 0;
    this.source = '';
    this.title = '';
    this.deleted = false;
    this.checked = false;
  …