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...