Parse classes by bones or introspect types in Typescript







β€œYou came up with a cool thing, Styopa,” a colleague told me, realizing the idea told to him. I hope this is true, although I will not say that there is something insanely innovative in what will be discussed later, however, in my opinion, this material is still of interest.

Today we'll talk about the use of introspection in the development of web interfaces, a little bit of generalized programming and reinvent the wheel in Typescript, which has a similar analogue in .NET.







?



, .







:







class Person {
    height: number;
    weight: number;
    bloodPressure: string;
}
      
      





, , , .













, - .







const fields = ObjectFields.of(Person)
      
      







, , , . Object.keys



, keyof



. , , .

, . , , .







interface IObjectField<T extends object> {
    readonly field: keyof T;
    readonly type: string;
    readonly value: any;
}
      
      





, , FieldInfo. :)

, Typescript β€” .NET. , . , C# .

, .







interface IConstructor<T> {
    new(...args: any[]): T;
}
      
      





, , :







  1. , β€” .
  2. IObjectField



  3. β€” .


Typescript.







class ObjectFields<T extends object> extends Array<IObjectField<T>> {
    readonly [n: number]: IObjectField<T>;
    constructor(type: IConstructor<T>) {
        const instance: T = new type();
        const fields: Array<IObjectField<T>> = (Object.keys(instance) as Array<keyof T>)
            .map(x => {
                const valueType = typeof instance[x];
                let result: IObjectField<T> = {
                    field: x,
                    type: valueType === 'object'
                        ? (instance[x] as unknown as object).constructor.name
                        : valueType,
                    value: instance[x]
                }
                return result;
            });
        super(...fields);
    }
}
      
      





"" Person



.







const fields = new ObjectFields(Person);
console.log(fields);
      
      





, .













? . , Object.keys



, Javascript, , . β€” , , , - . "", - .







class Person {
    height: number = 80;
    weight: number = 188;
    bloodPressure: string = '120-130 / 80-85';
}
      
      





β€” , .













.







class Material {
    name = "wood";
}

class MyTableClass {
    id = 1;
    title = "";
    isDeleted = false;
    createdAt = new Date();
    material = new Material();
}
      
      





.













?



The first thing that came to mind: CRUD applications in react can now be written by implementing generic components. For example, you need to make a form to insert into a table. Please, no one forbids doing something like that.







interface ITypedFormProps<T extends object> {
    type: IConstructor<T>;
}

function TypedForm<T extends object>(props: ITypedFormProps<T>) {
    return (
        <form>
            {new ObjectFields(props.type).map(f => mapFieldToInput(f))}
        </form>
    );
}
      
      





And then use this component like this.







<TypedForm
    type={Person} />
      
      





Well, the table itself can be made according to the same principle.







Summing up



I would like to say that the piece turned out to be interesting, but it is not yet clear what to do with it next. If you were interested or have any suggestions, write in the comments, but for now, see you soon! Thanks for attention!








All Articles