Hookyns / tst-reflect

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

[BUG] type metadata #76

Closed uplight-dev closed 1 year ago

uplight-dev commented 1 year ago

Describe the bug

Type introspection doesn't seem to work on types extending other types. Also, since types don't support decorators (i.e. @reflected), one has to manually write getType() in order to activate metadata generation for TypeA. Without this, the result contains invalid values, like "type.name : 'unknown'"

The code causing the problem

type TypeA = {
    prop1: string
}

type TypeB = TypeA & {
  prop2: string,
  prop3: string
}

const t0: Type = getType<TypeA>();
const t1: Type = getType<TypeB>();
console.log(t1.getProperties())

To Reproduce Steps to reproduce the behavior:

  1. Build,
  2. run,
  3. see error...

Expected behavior All properties including inherited ones should be displayed by console.log(t1.getProperties())

Runtime (please complete the following information):

Additional context

Hookyns commented 1 year ago

Hi @uplight-dev, TypeB is just a type alias for { prop1: string } & { prop2: string, prop3: string }, there is no type in the type checker, so it is described in metadata like an intersection.

So you have to do something like this:

const t1: Type = getType<TypeB>();

const props = [];

if (t1.isUnionOrIntersection()) {
  props.push(...t1.types[0].getProperties(), ...t1.types[1].getProperties());
} else {
  props.push(...t1.getProperties());
}

console.log(props.map((p) => p.name + ': ' + p.type.name));

Demo on StackBlitz.

Hookyns commented 1 year ago

Wrong demo link. Fixed.

Hookyns commented 1 year ago

BTW what do you mean by

one has to manually write getType() in order to activate metadata generation for TypeA

TypeA is reflected correctly in the demo if I reflect over TypeB only.

uplight-dev commented 1 year ago

Thank you, the demo works perfectly.

For the metadata generation, it's when you try to find the type in the TypeStore instead of using getType() construct. If I were to use classes iso types and add a @reflect() before each class, then metadata would get generated.

Please see: Demo

Hookyns commented 1 year ago

Okay, got it.

Sadly, this is intended behavior in the current version. This was intended as an optimisation, so only required types are reflected because of size of metadata (it would be megabytes for some projects). Type.find() was introduced later, but it is limited to reflected types.

New major version (alpha release is rly close) works in a different way (based on include/exclude options) so it works properly there.

uplight-dev commented 1 year ago

Looking forward to it! And thanks for this awesome lib, makes a difference for my use case!