3

我有以下课程:

export class SomeModel {
  prop1: number;
  prop2: number;
  comment: string;
}

以及以下动态获取其属性的方法:

getTypeProperties<T>(obj: T): string[] {
    const ret: string[] = [];
    for (const key in obj) {
      if (obj.hasOwnProperty(key))
        ret.push(key);
    }
    return ret;
}

以下调用返回一个空数组:

getTypeProperties(new SomeModel());

但是,如果我用 显式初始化所有属性null,则将正确返回属性:

export class SomeModel {
  prop1: number = null;
  prop2: number = null;
  comment: string = null;
}

问题:这是正常行为吗?或者是否有一个 TypeScript 编译器开关来切换它?

我不知道它是否相关,但这里是 tsconfig.json 内容:

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  }
}
4

1 回答 1

2

这是设计使然,字段声明不输出任何 JavaScript 代码,它们只是告诉编译器该字段存在(即,当我在代码中使用它时,它应该不会抱怨)并且是某种类型。在您第一次分配该字段之前,它不会存在于实例中,因此不会被迭代。如果您初始化该字段,它的值将被分配给构造函数中的实例,因此将变得可迭代。

正如您发现的那样,最简单的解决方法是为字段分配一个值,如果只有 value undefined

我们可以在为 ES5 生成的代码中看到这种行为。例如对于这个类

class A {
    nonInitField: number;
    initField = 0;
    test() {
        this.nonInitField = 0;// Can be used, and will be iterable after it is assigned
    }
}

生成此代码:

var A = /** @class */ (function () {
    function A() {
        this.initField = 0; // Iterable right away as it is assigned in the constructor
    }
    A.prototype.test = function () {
        this.nonInitField = 0; // Can be used, and will be iterable after it is assigned
    };
    return A;
}());
于 2018-06-27T08:06:42.477 回答