Analisa classes por bones ou introspectos tipos em Typescript







“Você veio com uma coisa legal, Styopa”, um colega me disse, percebendo a ideia que lhe foi transmitida. Espero que isso seja verdade, embora não vá dizer que há algo insanamente inovador no que será discutido mais tarde, no entanto, na minha opinião, este material ainda é de interesse.

Hoje vamos falar sobre o uso da introspecção no desenvolvimento de interfaces web, um pouco de programação generalizada e reinventar a roda no Typescript, que tem um análogo semelhante no .NET.







O que sabemos sobre introspecção?



, .







:







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();
}
      
      





.













?



A primeira coisa que veio à mente: aplicativos CRUD em react agora podem ser escritos implementando componentes genéricos. Por exemplo, você precisa fazer um formulário para inserir em uma tabela. Por favor, ninguém proíbe fazer algo assim.







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>
    );
}
      
      





E então use este componente assim.







<TypedForm
    type={Person} />
      
      





Bem, a própria mesa pode ser feita de acordo com o mesmo princípio.







Resumindo



Eu gostaria de dizer que a peça acabou sendo interessante, mas ainda não está claro o que fazer a seguir. Se você se interessou ou tem alguma sugestão, escreva nos comentários, mas por enquanto, nos vemos em breve! Obrigado pela atenção!








All Articles