How to iterate over non existent member of a class

2019-08-21 07:42发布

问题:

How do I achieve the following prototype-code:

class test {
    a: number;
    b: boolean;
    c: string;
}

for (const so in test)
    so, //'a', 'b', 'c'...
    //so.type //'number', 'boolean', 'string'...

I don't have any idea how to get the type however I tried creating a new object and iterating over it for the names but obviously this didn't work since the class members were left uninitialized.

回答1:

As suggested in the comment on the question, metadata could be used to some degree but it is messy.

First the decorator has to store all key names in a list because the properties do not actually exist on the prototype:

import 'reflect-metadata';

const propertiesSymbol = Symbol('properties');
const metadata = (target: any, key: string) => {
    let list = <string[] | undefined>target[propertiesSymbol];
    if (list == undefined)
        list = target[propertiesSymbol] = [];

    list.push(key);
};

This is used on the properties of the class:

class Test {
    @metadata
    a!: number;
    @metadata
    b!: boolean;
    @metadata
    c!: string;
}

To iterate the list can be retrieved from the symbol properties symbol slot and the getMetadata function can be used to get the generated design:type. This will be the type constructor, not the name.

for (const key of (Test.prototype as any)[propertiesSymbol])
    console.log(Reflect.getMetadata("design:type", Test.prototype, key));

This should print something like:

[Function: Number]
[Function: Boolean]
[Function: String]

Note that the compiler settings have to contain decorators & metadata flags:

"compilerOptions": {
    // ...
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
}