reactjs - Renderizado dinámico con React y Typescript
Usando React con TypeScript, intento renderizar componentes dinámicamente basándome en el nombre de un campo
// Referencing all components
const components = {
ComponentA,
ComponentB,
};
// Dynamic render the component based on fieldName
const displayComponent = (
fieldName: keyof typeof components,
content: ComponentType
): React.ReactNode => {
const FieldNameComponent = components[fieldName];
return <FieldNameComponent item={content} />;
};
Mis tipos:
type ComponentTypeA = {
title: string;
content: string;
};
type ComponentTypeB = {
title: string;
excerpt: string;
};
type ComponentType = ComponentTypeA | ComponentTypeB;
El compilador no está contento porque no sabe qué tipo usar (Component1 o Component2, que tienen propiedades diferentes). Recibo este error
El tipo 'ComponentType' no se puede asignar al tipo 'ComponentTypeA & ComponentTypeB'.
El tipo 'ComponentTypeA' no se puede asignar al tipo 'ComponentTypeB & ComponentTypeA'.
Al tipo 'ComponentTypeA' le faltan las siguientes propiedades del tipo 'ComponentTypeB': excerpt
Así que he intentado de esta manera:
const displayComponent = (
fieldName: keyof typeof components,
content: ComponentType
) => {
if (content instanceof ComponentTypeA) {
return <ComponentA item={content} />;
} else if (content instanceof ComponentTypeB) {
return <ComponentB item={content} />;
}
};
Pero el error permanece incluso con la prueba instanceof.
Respuesta #1
Podrías usar un guardia de tipo:
function isComponentTypeA(type: unknown): type is ComponentTypeA {
return type && "title" in type && "content" in type;
}
Y lo usarías en la condición:
if (isComponentTypeA(content)) {
return <ComponentA item={content} />; // inferred as ComponentTypeA
} else if (isComponentTypeB(content)) { // another type guard if needed
return <ComponentB item={content} />; // inferred as ComponentTypeB
}
Respuesta #2
Terminé resolviendo este error de esta manera:
const displayComponent = (
content: ComponentType
): React.ReactNode => {
switch (content.fieldName) {
case "ComponentA":
return <ComponentA item={ content as ComponentAType}/>
case "ComponentB":
return <ComponentB item={ content as ComponentBType}/>
default:
break;
}
};
Pero estoy bastante descontento con esto, porque si tengo que tratar con muchos componentes, la declaración switch será muy larga... Se agradece un mejor enfoque.
