Tengo un componente funcional muy simple de la siguiente manera:
import * as React from 'react'; export interface AuxProps { children: React.ReactNode } const aux = (props: AuxProps) => props.children; export default aux;Y otro componente:
import * as React from "react"; export interface LayoutProps { children: React.ReactNode } const layout = (props: LayoutProps) => ( <Aux> <div>Toolbar, SideDrawer, Backdrop</div> <main> {props.children} </main> <Aux/> ); export default layout;Sigo recibiendo el siguiente error:
[ts] El tipo de elemento JSX 'ReactNode' no es una función constructora para elementos JSX. El tipo 'indefinido' no se puede asignar al tipo 'ElementClass'. [2605]
¿Cómo escribo esto correctamente?
Para mí, la respuesta de @Sibren no fue lo suficientemente clara, pero encontré esta respuesta SO y la hice todo en línea (quizás no sea la forma más corta, pero sí la que encuentro más fácil de comprender).
function MyComponentWithChildren({ customProp, children, /*notice the children are implicit*/ }: React.PropsWithChildren<{ customProp: any }>) { return <div>{children}</div>; }import { ReactNode, FC } from 'react' type Props = { children: ReactNode } const App: FC<Props> = ({children}) => (<div>{children}</div>)También puede usar JSX.ElementChildrenAttribute
export default function Layout({children}: JSX.ElementChildrenAttribute) { return <div> {children} </div> }debe saber que cualquier componente de reacción debe devolver null o React.Element , pero el tipo de props.children es React.ReactNode , por lo que debe usar props.children dentro de un Element para hacer que babel configure el constructor del Element .
la segunda regla de cualquier componente de reacción es que la primera letra del nombre debe ser una letra mayúscula para permitir que la reacción reconozca que el componente no es una etiqueta html.
entonces el código debería ser así.
const Aux = (props: AuxProps) => <>props.children</>; otra pista si todavía usa mecanografiado, el componente funcional debería ser del tipo React.FC como este
type Props = { title: string; } const Aux:React.FC<Props> = (props) => ( <div> <h3>{props.title}</h3> { props.children } {/* children is exist by default in type React.FC */} </div> )Esto siempre me ha funcionado:
type Props = { children: JSX.Element; };Un React Node es uno de los siguientes tipos:
Boolean (que se ignora)null o undefined (que se ignora)NumberStringReact element (resultado de JSX )estoy usando lo siguiente
type Props = { children: React.ReactNode }; const MyComponent: React.FC<Props> = ({children}) => { return ( <div> { children } </div> ); export default MyComponent;Los componentes de React deben tener un solo nodo contenedor o devolver una matriz de nodos.
Su componente <Aux>...</Aux> tiene dos nodos div y main .
Intente envolver a sus hijos en un div en el componente Aux .
import * as React from 'react'; export interface AuxProps { children: React.ReactNode } const aux = (props: AuxProps) => (<div>{props.children}</div>); export default aux;Para usar <Aux> en su JSX, debe ser una función que devuelva ReactElement<any> | null Esa es la definición de un componente de función .
Sin embargo, actualmente se define como una función que devuelve React.ReactNode , que es un tipo mucho más amplio. Como dicen los tipos de React:
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined; Asegúrese de que los tipos no deseados se neutralicen envolviendo el valor devuelto en React Fragment ( <></> ):
const aux: React.FC<AuxProps> = props => <>{props.children}</>;Esto es lo que funcionó para mí:
interface Props { children: JSX.Element[] | JSX.Element } Editar , recomendaría usar children: React.ReactNode en su lugar ahora.
Solo children: React.ReactNode .
puedes declarar tu componente así:
const MyComponent: React.FunctionComponent = (props) => { return props.children; }La forma general de encontrar cualquier tipo es mediante el ejemplo. La belleza de mecanografiado es que tiene acceso a todos los tipos, siempre que tenga los archivos @types/ correctos.
Para responder a esto yo mismo, solo pensé en un componente de usos reactivos que tiene el apoyo de los children . ¿Lo primero que se te vino a la mente? ¿Qué tal un <div /> ?
Todo lo que necesita hacer es abrir vscode y crear un nuevo archivo .tsx en un proyecto de reacción con @types/react .
import React from 'react'; export default () => ( <div children={'test'} /> ); Al pasar el cursor sobre el apoyo de los children se muestra el tipo. ¿Y qué sabes? Su tipo es ReactNode (no es necesario ReactNode[] ).
Luego, si hace clic en la definición de tipo, lo lleva directamente a la definición de elementos secundarios children provienen de la interfaz DOMAttributes .
// node_modules/@types/react/index.d.ts interface DOMAttributes<T> { children?: ReactNode; ... }Nota: ¡Este proceso debe usarse para encontrar cualquier tipo desconocido! Todos ellos están ahí esperando a que los encuentres :)
Desde el sitio de TypeScript: https://github.com/Microsoft/TypeScript/issues/6471
La práctica recomendada es escribir el tipo de accesorios como {niños?: cualquiera}
Eso funcionó para mí. El nodo secundario puede ser muchas cosas diferentes, por lo que la tipificación explícita puede pasar por alto casos.
Hay una discusión más larga sobre el problema de seguimiento aquí: https://github.com/Microsoft/TypeScript/issues/13618 , pero el enfoque any todavía funciona.
Como un tipo que contiene niños, estoy usando:
type ChildrenContainer = Pick<JSX.IntrinsicElements["div"], "children">Este tipo de contenedor secundario es lo suficientemente genérico para admitir todos los casos diferentes y también está alineado con la API de ReactJS.
Entonces, para tu ejemplo sería algo como:
const layout = ({ children }: ChildrenContainer) => ( <Aux> <div>Toolbar, SideDrawer, Backdrop</div> <main> {children} </main> <Aux/> )El tipo de retorno del componente de función está limitado a JSXElement | null en TypeScript. Esta es una limitación de tipo actual, React puro permite más tipos de devolución.
Fragmento de demostración mínimo
Puede usar una aserción de tipo o Fragmentos como solución alternativa:
const Aux = (props: AuxProps) => <>props.children</>; const Aux2 = (props: AuxProps) => props.children as ReactElement;ReactNode children: React.ReactNode podría ser subóptimo, si el objetivo es tener tipos fuertes para Aux .
Se puede asignar casi cualquier cosa al tipo ReactNode actual, que es equivalente a {} | undefined | null Un tipo más seguro para su caso podría ser:
interface AuxProps { children: ReactElement | ReactElement[] }Ejemplo:
Dado que Aux necesita elementos React como elementos children , accidentalmente le agregamos una string . Entonces, la solución anterior generaría un error en contraste con ReactNode : eche un vistazo a los patios de recreo vinculados.
Los children escritos también son útiles para accesorios que no son JSX, como una devolución de llamada deRender Prop .
Estas respuestas parecen estar desactualizadas: React ahora tiene un tipo PropsWithChildren<{}> . Se define de manera similar a algunas de las respuestas correctas en esta página:
type PropsWithChildren<P> = P & { children?: ReactNode };
Puedes usar ReactChildren y ReactChild :
import React, { ReactChildren, ReactChild } from 'react'; interface AuxProps { children: ReactChild | ReactChildren; } const Aux = ({ children }: AuxProps) => (<div>{children}</div>); export default Aux;Si necesita pasar matrices planas de elementos:
interface AuxProps { children: ReactChild | ReactChild[] | ReactChildren | ReactChildren[]; }También puede usar React.PropsWithChildren<P> .
type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;