I'm using reflect-metadata lib and Typescript decorators.
I have this class for example (real one will have much more fields):
class Message {
@FieldTyping
text: string;
@FieldTyping
code: number;
constructor(text: string, code: number) {
this.text = text;
this.code = code;
}
}
Decorator quite synthetic too, but in real code it doing eventually this:
function FieldTyping(target: Object, key: string) {
Reflect.getMetadata('design:type', target, key)
// "String" output in console for "text" key
}
Now it works correctly, but I want to reduce boilerplate. So I want to use one decorator and declare all fields in constructor, like:
@ClassTyping
class Message {
constructor(public text: string, public code: number) { }
}
Decorator should iterate over all public fields and do the same work as FieldTyping - getting actual type from reflect. So I want two things:
- Get all keys from the class. (as I need only
stringnames) - Get right
targetforReflect.getMetadata.
But target in the class decorator is a constructor, not Object. I was able to get access to class keys with some "hack":
type ConstructorType<T> = {
new (...args: any[]): T
}
function ClassTyping<T>(target: ConstructorType<T>) {
const obj = new target()
const fields = Object.keys(obj)
fields.map(prop => Reflect.getMetadata('design:type', target, field))
// "undefined" output for all fields
}
So I create class instance with undefined values and get it keys (public fields) without knowing its actual type. But I have problem with target. I tried to use any variations in this context instead actual target argument:
target.prototypein order to getObjectfrom it constructor;objas a new instance of thisObject;- just
Messageas a type
But none of them worked, I got "undefined" type in all cases. From my experiments it seems like in any other place Reflect.getMetadata don't work too, even without decorators and with simple parameters:
Reflect.getMetadata('design:type', Message, "text")
Apparently it works only with target from field decorator, at least for me. I was digged through whole SO in this theme and didn't find any appropriate solution for my specific purposes.
So please tell if this is possible at all or what I missing.
Note that:
- I know it's definitly possible with regex, but I don't want such ugly solution.
- It's client code, so I can't get access to filesystem and parse sources to get types with ts-morph, for example (or I missing something, again)
- I do have
"emitDecoratorMetadata": truein mytsconfig.json - My stack is just NPM and Parcel as bundler. Works with Parcel dev server in local environment and with Harp in "production" (on Heroku).