Dynamic infer type

Discussão em 'Angular' iniciado por Jacopo Sciampi, Março 6, 2025.

  1. I have an object like this

    export const MyVariable = {
    'test': {
    protected: false,
    body: [
    {
    field: 'name',
    type: 'string',
    validators: ['MAX_CHAR_16']
    },
    {
    field: 'surname',
    type: 'string',
    }
    ]
    }
    }


    and I'm trying to get the body as a type dinamically.

    So far I've tried a double infer :

    type InferBodyType<T extends { body?: readonly SchemaField[] }> = T['body'] extends readonly SchemaField[]
    ? {
    [K in T['body'][number] as K['field']]: ExtractSchemaFieldType<K>;
    }
    : unknown;

    type ExtractSchemaFieldType<T extends SchemaField> = T['type'] extends 'string' ? string : T['type'] extends 'number' ? number : unknown;


    but since field is an array, I can't find a way to extract the type.

    For instance, this is of type unknown while it should be of type {name: string; password: string}

    I don't know if this is possible, what I'm trying to achieve is to not create a blotload of types and interfaces.

    The complete real example can be copied from here below:

    export const BODY_VALIDATOR = {
    MAX_CHAR_16: /^.{1,16}$/,
    SPECIAL_CHAR: /^(?=.*[!@#$%^&*()_+{}\[\]:;<>,.?~\\/-]).+$/,
    EMAIL: /^[a-zA-Z0-9._%+-]{1,32}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
    };

    export type StaticMethods<T> = {
    [K in Exclude<keyof T, 'register' | 'prototype'>]: T[K] extends (...args: any[]) => any ? T[K] : never;
    };

    export type AuthFunctionList = StaticMethods<typeof __ServerRoute__Auth>;


    export type CustomSchema<TComponent> = {
    [key: string]: CustomSchemaDefinition<TComponent>;
    };

    export type CustomSchemaDefinition<TComponent> = {
    method: HttpMethods;
    fnToCall: keyof TComponent;
    /** If true, checks for the token in the header */
    protected?: boolean;
    body?: SchemaField[];
    };

    export type SchemaField = {
    field: string;
    type: 'string' | 'number';
    validators: (keyof typeof BODY_VALIDATOR)[];
    };

    export type HttpMethods = 'post' | 'get' | 'put' | 'patch' | 'delete';


    export const $SCHEMA__AUTH: CustomSchema<AuthFunctionList> = {
    '/v1/auth/create': {
    protected: false,
    method: 'post',
    fnToCall: 'create',
    body: [
    {
    field: 'username',
    type: 'string',
    validators: ['MAX_CHAR_16']
    },
    {
    field: 'password',
    type: 'string',
    validators: ['MAX_CHAR_16', 'SPECIAL_CHAR']
    },
    {
    field: 'email',
    type: 'string',
    validators: ['EMAIL']
    }
    ]
    },
    '/v1/auth/login': {
    protected: true,
    method: 'post',
    fnToCall: 'create',
    body: [
    {
    field: 'username',
    type: 'string',
    validators: ['MAX_CHAR_16']
    },
    {
    field: 'password',
    type: 'string',
    validators: ['MAX_CHAR_16', 'SPECIAL_CHAR']
    }
    ]
    }
    };



    export class __ServerRoute__Auth {
    public static create(/* fastify request | reply*/): void {
    let fastifyBody: unknown; // this is here just for testing purpose.
    // request.body from fastify is of type unknown

    // as you can see newBody is 'unknown'
    const newBody = someFunction(fastifyBody, '/v1/auth/create', $SCHEMA__AUTH);

    reply.code(200).send({});
    }

    public static login(/* fastify request | reply*/): void {
    reply.code(200).send({ message: 'ok' });
    }
    }

    function someFunction<TComponent, T extends keyof CustomSchema<TComponent>>(
    body: any,
    path: T,
    schema: CustomSchema<TComponent>
    ): InferBodyType<CustomSchema<TComponent>[T]> {
    const schemaDefinition = schema[path];
    if (!schemaDefinition || !schemaDefinition.body) {
    return body;
    }

    const typedBody: { [key: string]: any } = {};
    schemaDefinition.body.forEach((field) => {
    if (body[field.field] !== undefined) {
    typedBody[field.field] = body[field.field];
    }
    });

    return typedBody as InferBodyType<CustomSchema<TComponent>[T]>;
    }

    type InferBodyType<T extends { body?: readonly SchemaField[] }> = T['body'] extends readonly SchemaField[]
    ? {
    [K in T['body'][number] as K['field']]: ExtractSchemaFieldType<K>;
    }
    : unknown;

    type ExtractSchemaFieldType<T extends SchemaField> = T['type'] extends 'string' ? string : T['type'] extends 'number' ? number : unknown;

    Continue reading...

Compartilhe esta Página