reactjs - Al tipo 'Element[]' le faltan las siguientes propiedades al manejar hijos de React
Tengo un componente padre que proporciona sus hijos a un componente hijo. Los hijos pueden ser un nodo o un arreglo de nodos, y dependiendo de si es un nodo o un arreglo de nodos, los hijos en el ComponenteHijo se renderizan de manera diferente. Sin embargo, cuando renderizo el ComponenteHijo en el ComponentePadre, obtengo el siguiente error de Typescript:
TS2786: 'ChildComponent' no se puede usar como un componente JSX. Su tipo de retorno 'Element | Element[]' no es un elemento JSX válido. Al tipo 'Element[]' le faltan las siguientes propiedades del tipo 'Element': type, props, key
Por favor, vea a continuación el código. ¿Cómo puedo renderizar el ChildComponent sin ningún error de Typescript? ¡Gracias!
import React from 'react';
import styles from './component.scss';
interface Props {
children: React.ReactChildren;
}
const ChildComponent = ({ children }: Props): JSX.Element | JSX.Element[] => {
if (React.Children.count(children)) {
return React.Children.map(children, (child) => (
<div className={styles.childContainer}>{child}</div>
));
}
return <div className={styles.singleContainer}>{children}</div>;
};
const ParentComponent: React.FC<Props> = ({ children }) => (
<div className={styles.container}>
<ChildComponent>{children}</ChildComponent>
</div>
);
export default ParentComponent;
Respuesta #1
En tu código actual, el tipo de retorno es JSX.Element[] desde el bloque if (incorrecto) pero JSX.Element (correcto) desde la parte else. Esa es la razón del error que estás viendo.
Para solucionarlo, necesitas devolver una sola expresión JSX desde ChildComponent ya que "las expresiones JSX deben tener un elemento padre".
Puedes usar un elemento padre como div, span o simplemente usar React.Fragment (abreviatura <></>):
const ChildComponent = ({ children }: Props) => {
if (React.Children.count(children)) {
return (
<> // HERE
{React.Children.map(children, (child) => (
<div className={styles.childContainer}>{child}</div>
))}
</>
);
}
return <div className={styles.singleContainer}>{children}</div>;
};
Y el tipo children debería ser ReactNode en lugar de ReactChildren:
interface Props {
children: React.ReactNode;
}
Como estas son las definiciones de ambos tipos:
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
interface ReactChildren {
map<T, C>(children: C | C[], fn: (child: C, index: number) => T):
C extends null | undefined ? C : Array<Exclude<T, boolean | null | undefined>>;
forEach<C>(children: C | C[], fn: (child: C, index: number) => void): void;
count(children: any): number;
only<C>(children: C): C extends any[] ? never : C;
toArray(children: ReactNode | ReactNode[]): Array<Exclude<ReactNode, boolean | null | undefined>>;
}
Además, sugeriría no usar React.FC.
Aquí hay una demostración.
Editar :
PD: El bloque else <div className={styles.singleContainer}>{children}</div> y la condición if con count realmente no son necesarios.
