如何在 TypeScript 中循环访问类的属性?以以下类为例:
export class Task implements Itask {
public Id: number = 0;
public Name: string;
public Description: string;
public Completed: boolean = false;
public TaskType: TaskType;
}
我想检索属性,因此: ["Id", 名称", "描述", "已完成", "任务类型"]
试
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;
};
不幸的是,没有成功,我知道使用"TodoApp.Task.arguments"是不正确的。但是,有人可以告诉我正确的方法吗?
让我们考虑所有"未定义"的属性,即打字稿类中定义的所有属性,例如(我写了"未定义"而不是undefined
,原因将在下面明确
class A {
prop1: string
prop2: number
}
不会被任何Object.keys
或this.hasOwnProperty(k)
枚举,因为Autogen JavaScript不知道这些属性。当您创建打字稿类时,您只有一个选择,即将所有属性初始化为默认值,例如
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];
}
}
如果您不喜欢默认值解决方案,您仍然可以使用 magic undefined
javascript 关键字执行此操作,以便执行以下操作:
class A {
prop1: string = undefined
prop2: number = undefined
}
此时,javascript 对应项将拥有模型中的所有属性,您将使用 Object.keys(this)
迭代它们或通过this.hasOwnProperty
检查它们
请参阅如何遍历或枚举 JavaScript 对象?
在您的情况下,如下所示:
for (var i in TodoApp.Task) {
if (TodoApp.Task.hasOwnProperty(i)) {
var th = $('<th />').append(TodoApp.Task[i]);
tHead.append(th);
}
}
这是我的答案,基于以下解释的问题:
如何在运行时迭代 TypeScript 声明的类或其他声明接口(甚至对象类型)的(公共)属性的枚举?
这个问题可以更改为使用私有类成员,因为它们可以在任一范围内访问。
答:不行,可惜。要接近它,您唯一能做的就是以下内容。这有望解释这里的问答与一些 TS 开发人员可能真正想要做的事情之间的歧义:
(在下面的 TS 操场上检查/运行此代码)
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
}
请注意,到目前为止,没有任何方法可以在编译时检查IFooProps
并且IFoo
实际匹配(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 操场上运行这个)
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
从javascript迁移到typescript时,我遇到了类似的问题,我的javascript代码正在循环对象的属性。
较旧的答案给出了类型安全的解决方案,这个答案不是类型安全的,只是避免了使用类型转换的打字稿错误。这意味着,如果分配无效属性或为属性分配具有错误类型的值,打字稿不会生成错误。
循环属性的示例 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并且没有很多需要不安全代码的情况,那么将代码转换为打字稿可能有足够的好处来接受一些不安全的情况。