Hookyns / tst-reflect

Advanced TypeScript runtime reflection system
MIT License
328 stars 11 forks source link

Add support of `isDefaultValueAvailable` and `getDefaultValue` on PropertyInfo and Parameter types #66

Open leohubert opened 1 year ago

leohubert commented 1 year ago

Hi all!

In a DI project, I need to know if a parameter in a class constructor function has a default value. And also I need to be able to get the default value if needed.

This can be useful for classic methods or class properties.

Hookyns commented 1 year ago

Detect if the parameter has initializer (that's how TypeScript compiler calls default value) is simple, if the parameter is rest parameter (...foo) too. But I have to think about the default value, because it is not easy to get it in "static" context,.. somewhere in the metadata.

Imagine that the initializer of the parameter is class instantiation. If you reflect over such function/method from other file, you will not have reference to that class. So you have to import it dynamically, that means import(): Promise.

What if that class is not exported from that module?

I'm able to get static values such as string, number and boolean literals as I do it in decorators.

Hookyns commented 1 year ago

Hmm this will be the most problematic case IMHO.

class Foo {
    constructor(private _foo: any) {}

    foo(foo: any = this._foo) {

    }
}

Initializer is this._foo. That cannot be solved.

Hookyns commented 1 year ago

I implemented the simple part in v1 (detection if the parameter is the rest parameter, if it has initializer and serialization of constant initializer).

Hookyns commented 1 year ago

Your investigation around param = new Something() initializers is still relevant.

leohubert commented 1 year ago

Your investigation around param = new Something() initializers is still relevant.

I think I have a lead.

Hookyns commented 1 year ago

@leohubert What if we do something like this in runtime?

class ParameterInfo {
    ....
    +++ get initializer(): Initializer;
    ...
}

class Initializer {
    isConstant(): this is ConstantInitializer;
    isInstance(): this is InstanceInitializer ;
}

class ConstantInitializer extends Initializer {
    get value(): any;
}

class InstanceInitializer extends Initializer {
    get type(): Type;
    getValue(): Promise<any>;
}

Transformer just has to detect the type; maybe the constant arguments too? In the v1 this is super easy solution.