在类类型属性

时间:2015-06-19 18:15:18

标签: typescript reflection

如何在TypeScript中循环遍历类的属性? 以下面的课程为例:

export class Task implements Itask {
  public Id: number = 0;
  public Name: string;
  public Description: string;
  public Completed: boolean = false;
  public TaskType: TaskType;
}

我想检索属性,因此:[" Id",Name"," Description"," Completed"," TaskType& #34;]

尝试

GetTaskHeaders = () => {
  const _self = this;
  const tHead = $('<thead />').append('<tr />');

  for (let i = 0; typeof TodoApp.Task.arguments; i++) {
    const th = $('<th />');
    th.append(TodoApp.Task.arguments[i]);
    tHead.append(th);
  }

  console.log(tHead);

  return tHead;
};  

不幸的是,没有成功,我知道使用&#34; TodoApp.Task.arguments&#34;是不正确的。 但是,有人能告诉我正确的方法吗?

4 个答案:

答案 0 :(得分:11)

让我们考虑所有&#34;未定义&#34;属性,即在typescript类中定义的所有属性,如(我写了&#34;未定义&#34;而不是undefined,原因将在下面明确说明)

class A { 

   prop1: string
   prop2: number

} 
任何Object.keysthis.hasOwnProperty(k)都不会枚举

,因为autogen javascript不知道这些属性。 创建typescript类时,只有一个选项,即将所有属性初始化为默认值,如

class A { 

   prop1: string
   prop2: number
   prop3: B

   constructor() {
     this.prop1="";
     this.prop2=-1;
     this.prop3=null;
   }

} 

此时,您将获得A实例的所有属性,例如在字典中的映射迭代中

var a = new A();
for (var i in properties) {
   if (a.hasOwnProperty(i)) {
      a[i]=properties[i];
   }
}

如果您不喜欢默认值解决方案,您仍然可以使用神奇的undefined javascript关键字执行此操作,以便执行以下操作:

class A { 

   prop1: string = undefined
   prop2: number = undefined

} 

此时,javascript对应项将包含模型中的所有属性,您将使用Object.keys(this)进行迭代,或通过this.hasOwnProperty

进行检查

答案 1 :(得分:9)

请参阅How do I loop through or enumerate a JavaScript object?

在您的情况下,例如:

for (var i in TodoApp.Task) {
    if (TodoApp.Task.hasOwnProperty(i)) {
        var th = $('<th />').append(TodoApp.Task[i]);
        tHead.append(th);
    }
}

答案 2 :(得分:1)

这是我的回答,基于以下解释的问题:

<块引用>

如何在运行时迭代 TypeScript 声明的类或其他声明的接口(甚至对象类型)的(公共)属性的枚举?

而且问题可以是使用私有类成员,因为它们可以在任一范围内访问。

答案:做不到。很遗憾。您可以做的唯一一件事就是接近它。这有望解释此处 Q/As 之间的歧义,以及一些 TS 开发人员可能真正想做的事情:

(在 TS 游乐场 here 上检查/运行下面的代码)

interface IFoo {
   firstProp: number
   secondProp: number
}

class Foo implements IFoo {
    readonly firstProp = 100;
    readonly secondProp = 200;
    someOtherProp = "bar";
}

enum IFooProps {
  firstProp,
  secondProp
}

for (key in Object.keys(IFooProps)) { // or at best IFoo, not needing to use an enum
  // ... do something with interface keys
}

请注意,目前还没有任何方法可以在编译时检查 IFooPropsIFoo 是否实际匹配(TS 功能请求...)。

而且,上面的方法不太好用,因为枚举对象的键也包括它的 ...

但是,现在要解决这个问题,我们可以这样做:

const foo = new Foo();
Object.keys(IFooProps).forEach(prop => {
  if (!isNaN(Number(prop))) return;
  console.log(foo[prop]) // prints value of all IFoo implementations
});

// OR (this is just a "nicer" way to effectively run the same code as above here ^)

// can only be done with "runtime alive" objects (enums are, but class/interface are types not objects, 
// but enums are also types too ;))
function enumKeys<O extends object, K extends keyof O = keyof O>(obj: O): K[] {
    return Object.keys(obj).filter(k => Number.isNaN(+k)) as K[];
}

enumKeys(IFooProps).forEach(prop => {
    console.log(foo[prop]) 
})

如果 TypeScript 允许检查 IFooProps 是否实际枚举了 IFoo 的属性(或者编译器允许从任何声明的接口显式或隐式地声明/生成这样的枚举),那么这实际上是类型安全的(而且方便)。

目前,这是一个相当笨拙的解决方法,需要“两次”声明接口(在枚举中是多余的)。

归功于:https://www.petermorlion.com/iterating-a-typescript-enum/ (用于帮助 enumKeys 助手)

编辑:

对这个问题的另一种可能解释(或确保澄清我们上面所说的内容):

<块引用>

在编译时使用接口键的枚举(仅)

是的,可以枚举接口,但不能在运行时:

(在 TS playground here 中运行)

interface IBar {
  firstThing: [string, string]
  secondThing: [number, number]
}

function doThatWithTypedThing<Key extends keyof IBar>(someDeclaredThingKey: Key, someDeclaredThing: IBar[Key]) {
  console.log(someDeclaredThingKey, someDeclaredThing)
}

const bar: IBar = {
  firstThing: ["bli", "bla"],
  secondThing: [400, 500]
}

doThatWithTypedThing("firstThing", bar.firstThing) // prints: firstThing [ "bli", "bla" ]
doThatWithTypedThing("secondThing", bar.secondThing) // prints: secondThing [ 400, 500 ]
doThatWithTypedThing("firstThing", bar.secondThing) // <- compiler error 2345
doThatWithTypedThing("notFirstThing", bar.secondThing) // <- other compiler error 2345

答案 3 :(得分:0)

我在从 javascript 迁移到 typescript 时遇到了类似的问题,并且我的 javascript 代码在对象的属性上循环。

较旧的答案给出了类型安全的解决方案,这个答案不是类型安全的,只是使用类型转换避免了打字稿错误。这意味着如果您分配无效的属性或为属性分配错误类型的值,typescript 不会产生错误。

循环属性的 javascript 示例:

function loop_over_props(object) {
  for (let k in object)
    console.log(object[k]);
}

做同样事情的打字稿:

interface HashMap<T> {
  [key: string]: T;
};

type SomeType = {
  field1: number;
  field2: string;
  field3: number;
};

function loop_over_props(object: SomeType) {
  var casted_object: HashMap<any> = <HashMap<any>>object;
  for (let k in casted_object)
    console.log(casted_object[k]);
}

对于像我这样的情况,您正在迁移现有的 javascript 并且没有很多需要不安全代码的情况,那么将代码转换为 typescript 可能有足够的好处来接受一些不安全的情况。