Hookyns / tst-reflect

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

[BUG] Union properties are broken #83

Open AntonC9018 opened 1 year ago

AntonC9018 commented 1 year ago

Consider the following code:

import {getType,Type} from "tst-reflect";
class A
{
    s?: string | undefined;
} 
console.log(getType<number|string>().isUnion());
console.log(getType<A>().getProperties().find(p => p.name == "s")!.type.isUnion());

The first check works fine and returns true. In the second check, the type of s is clearly a union, but it returns false. The same thing happens if I try to extract the types — the first statement correctly returns the two types, while the second one sometimes returns an empty array and sometimes return undefined. I'm using Vite with HMR (btw the hot reloading doesn't trigger when the transformed input changes, it may or may not be a problem on your side of things).

Hookyns commented 1 year ago

Hi, do you have strictNullChecks option in tsconfig enabled?

Hookyns commented 1 year ago

Check the issue #45

aj-bartocci commented 1 year ago

I'm similarly seeing some weirdness when using optional properties or unions. However isUnion() does appear to be returning correct values for me. However the type itself is being shown as a container which I'm not sure if that is intended.

I have strictNullChecks enabled.

import { getType } from "tst-reflect";

function printTypeProperties<TType>() {
    const type = getType<TType>(); // <<== get type of type parameter TType

    console.log(type.getProperties().map(prop => prop.name + ": " + prop.type.name + `, isOptional: ${prop.optional}` + `, isUnion: ${prop.type.isUnion()}` + `, type: ${prop.type}`).join("\n"));
}

interface SomeType {
    foo: string;
    bar?: number;
    baz: boolean | undefined;
}

printTypeProperties<SomeType>();
/*
Prints: 
foo: String, isOptional: false, isUnion: false, type: {Native String (String)}
bar: bar, isOptional: true, isUnion: true, type: {Container bar (bar)}
baz: baz, isOptional: false, isUnion: true, type: {Container baz (baz)}

*/

I was hoping the that the type name for bar would be something like Optional String and baz would be something like Union boolean, undefined

Sorry if I'm hijacking the thread it just seemed like the issues might be related. I can open a new issue if that would be better.

Hookyns commented 1 year ago

@aj-bartocci Container is meant to be a wrapper for all types consisting of multiple other types, such as Union, Intersection and Enum (which is union), but it wasn't good design decision so it is fixed in the new major version (not published yet) - Union, Intersection, Enum etc have own types.

Each container type has multiple types inside. You can access them via types property, eg. prop.type.types.

About naming... Class has name, interface has name, function has name, type alias has name but other types (such as types of properties, fields, parameters etc.) don't have names in TS. So names of those containers are not intended.

aj-bartocci commented 1 year ago

Got it that makes sense. Using prop.type.types should fit my needs. Thank you for creating this library by the way it's very cool.