Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

163
Vistas
How to generate React components dynamically using an array of Props in TypeScript?

I've been tackling an issue of abstracting out some logic for component creation in order to reduce a lot of duplication. As part of this, I have a generic Builder component which I use to dynamically render components baased on the props provided.

The issue comes from the fact that I defined elements as similar to the following:

type InputMap = typeof INPUTS
const INPUTS = {
  text: {
    component: TextInput,
    controlled: false
  },
  select: {
    component: Select
    controlled: true
  }
}

// Props for TextInput component
type TextProps = {
  onChange: (e: ChangeEvent<HTMLInputElement>) => void
  onBlur: (e: ChangeEvent<HTMLInputElement>) => void
}

// Props for Select component
type ElementProps = {
  onChange: (value: string) => void
  onBlur: () => void
}

I want to pass on my fields in a format similar to this:

const fields = [
  {
    input: "text",
    props: {
      onChange: e => console.log(e.target.value)

    }
  },
  {
    input: "select",
    props: {
      onChange: value => console.log(value)
    }
  }
]

This is the type I came up with:

import { ComponentProps } from "react";

export type FieldConfig<T extends FieldValues, K extends keyof InputMap> = {
  input: K;
  props?: ComponentProps<InputMap[K]["Component"]>
};

However in my Builder component, there's an issue when rendering the component.

<div>
  { fields.map(({ input, props }) => {
    const { Component, controlled } = INPUTS[input]
    return <Component {...props} /> // ERROR HERE
  })}
</div>
const { input, props } = field

TypeScript at that point gives me the following error:

Types of property 'onBlur' are incompatible.
Type 'ChangeHandler' is not assignable to type '() => void' 

Is there any way for me to narrow the types from a union to a specific instance of that union in this case? I'm trying my best to avoid any type assertions here. Any help would be greatly appreciated!

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

You can use a common field interface and a union type to define how your form structure should be handled like this.

interface FieldDefinition<TType extends string, TElement extends HTMLElement> {
    input: TType
    placeholder?: string
    onChange?: React.ChangeEventHandler<TElement>
    onBlur?: React.ChangeEventHandler<TElement>
}

interface TextField extends FieldDefinition<'text', HTMLInputElement> {
}

interface SelectField extends FieldDefinition<'select', HTMLSelectElement> {
    options: Record<PropertyKey, any>
}

type FormField = TextField | SelectField

const formFields: FormField[] = [
    {
        input: 'text',
        onChange: (event) => console.log(event.target.value)
    },
    {
        input: 'select',
        onChange: (event) => console.log(event.target.value),
        options: {
            foo: 'Foo',
            bar: 'Bar',
            baz: 'Baz'
        }
    }
]

This allows it to be properly used when returning the JSX, here's a link to a TypeScript playground showing it used as a component.

This has the added bonus of allowing you to define specific type specific properties that can be defined like an options object for the select input.

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda