@types/react
y tuve problemas.Definitions by:
en index.d.ts
) para que puedan responder.Los siguientes componentes
const SFC: React.StatelessComponent = (props) => props.children;
class C extends React.Component {
render() {
return this.props.children;
}
}
dar los errores
Type '(props: { children?: ReactNode; }) => ReactNode' is not assignable to type 'StatelessComponent<{}>'.
Type 'ReactNode' is not assignable to type 'ReactElement<any> | null'.
Type 'undefined' is not assignable to type 'ReactElement<any> | null'.
Class 'C' incorrectly extends base class 'Component<{}, {}>'.
Types of property 'render' are incompatible.
Type '() => ReactNode' is not assignable to type '() => false | Element | null'.
Type 'ReactNode' is not assignable to type 'false | Element | null'.
Type 'undefined' is not assignable to type 'false | Element | null'.
Funciona si envuelves children
en un Element
.
Devolver children
es bastante común cuando se crean componentes de proveedor que solo agregan algo a context
.
Probé las siguientes correcciones a index.d.ts
- render(): JSX.Element | null | false;
+ render(): ReactNode;
- (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
+ (props: P & { children?: ReactNode }, context?: any): ReactNode;
pero tengo errores por todas partes cuando intento quitar la pelusa que no estoy seguro de cómo solucionar.
TypeScript compile error: JSX element type 'ReactNode' is not a constructor function for JSX elements.
No, este cambio es incorrecto. No puede devolver múltiples elementos en React actualmente. Incluso si lo hace en algún lugar, lo más probable es que esté encapsulado en uno solo de alguna manera.
Solo en React 16 con Fiber esto podría ser posible :)
no estoy seguro de si cambiaron el comportamiento de reacción, pero el autor de redux / react mostró la capacidad de devolver this.props.children para crear envolturas delgadas (solo para agregar childContext a los elementos), como se ve en https://egghead.io/lessons/ javascript-redux-passing-the-store-down-implícitamente-a través de contexto
Sin embargo, react-native le permite devolver una matriz de elementos JSX desde el renderizado. una solución es envolver el this.props.children
con React.Children.only(this.props.children)
y arrojará si hay más de un solo elemento como raíz
Correcto, puede usar React.Children.only
pero tanto ReactNode
Y ReactElement
son valores válidos de this.props.children
.
const Title = props => <h1>{props.children}</h1>;
<Title>Woah</Title>
es un código React válido y razonable.
Puede devolver una matriz de elementos en la reacción 16, pero TS arroja un error porque cree que no puede.
Editar: haz esto children: JSX.Element[];
para arreglarlo
Según mi experiencia hasta ahora, parece que ReactNode debería ser válido.
const Id: React.SFC<{}> = (props) => props.children
const App = ()= > <Id>This should work but instead fails</Id>
¿Hay alguna posibilidad de que esto se refleje en @types/react
?
Sin esto, no puedo escribir React children.
Actualmente estoy envolviendo children
en React.Fragment
para evitar esto.
¿Alguna actualización al respecto?
No estoy seguro de si esto es más o menos correcto que envolver children
en un React.Fragment
, pero he tenido suerte al hacerlo
return (children as React.ReactElement);
return <>{foo(}</>;
toda la noche. <>
es una solución alternativa.
Esto también me está causando problemas.
Tengo un HOC que agrega accesorios a un componente dado y estoy tratando de usarlo con un componente funcional que tiene return children;
. Solo funciona si uso la solución alternativa return <>{children}</>;
.
Aquí hay una versión simplificada del HOC:
export interface ExtraProps {
extraProp1: string;
}
export const withExtraProps = <P extends object>(Component: React.ComponentType<P>) => {
return class extends React.Component<Omit<P, keyof ExtraProps>> {
render() {
const extraProps = {
extraProp1: 'test'
};
return (
<Component {...this.props as P} {...extraProps} />
)
}
}
}
Aquí hay una versión simplificada del componente funcional:
interface ComponentProps extends ExtraProps {
children?: React.ReactNode;
loadingComponent?: ReactElement;
}
export function ExampleComponent(props: ComponentProps) {
const { children, loadingComponent } = props;
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
await someAsyncCall();
setLoading(false);
}
fetchData();
});
if (loading) {
return loadingComponent || null;
}
return children;
}
// This line errors:
export const FeatureFlag = withExtraProps(ExampleComponent);
Obtuve el siguiente error:
Argument of type '(props: ComponentProps) => {} | null | undefined' is not assignable to parameter of type 'ComponentType<ComponentProps>'.
Type '(props: ComponentProps) => {} | null | undefined' is not assignable to type 'FunctionComponent<ComponentProps>'.
Type '{} | null | undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
Type 'undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
Si agrego un tipo de retorno de ReactElement | null
al ExampleComponent, deja de quejarse de pasarlo al HOC, pero sigue teniendo errores cuando devuelvo a los elementos secundarios:
export function ExampleComponent(props: ComponentProps): ReactElement | null {
...
...
return children; // Type 'ReactNode' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
}
Al igual que con los otros aquí, si lo cambio a return <>{children}</>;
, funciona, pero se siente asqueroso e innecesario.
Tengo el mismo problema _exacto_ que @kyrstenkelly : se pasa una función HOC a React.FC
que representa a sus hijos.
La solución <> children(...) </>
funciona, pero ¿hay una solución mejor todavía?
¡También tengo este problema! Actualmente estoy haciendo la solución sugerida de la solución de envoltura con React.Fragment
Aquí igual
interface IIntlMessageProps {
id: string;
valuesGiven?: {[key:string]:string};
}
// this doesn't work - -- TS2769 Type 'null' is not assignable to type '(nodes:ReactNodeARray) => ReactNode' | ... | undefined
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
return (
<FormattedMessage id={props.id} values={props.valuesGiven}>
{props.children}
</FormattedMessage>
)
};
//Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
return (
<FormattedMessage id={props.id} values={props.valuesGiven}>
<React.Fragment>{props.children}</React.Fragment>
</FormattedMessage>
)
};
// Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> | null = (props) => {
return (
<FormattedMessage id={props.id} values={props.valuesGiven}>
<>{props.children}</>
</FormattedMessage>
)
};
// Nope -- TS2769 Type '{}' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
return (
<FormattedMessage id={props.id} values={props.valuesGiven}>
{props.children ? props.children : undefined}
</FormattedMessage>
)
};
Creo que he probado todo lo que se aconseja aquí... :( ¿Alguna pista?
La solución es que necesitas envolverlo en un fragmento.
import React from 'react'
const Something: React.FC = ({ children }) => (
<> { children } </>
)
esto solucionará el error Type '({ children }: { children?: ReactNode; }) => ReactNode' is not assignable to type 'FunctionComponent
.
Si es posible, me gustaría evitar los fragmentos y hacer que el sistema de tipos JSX admita los mismos tipos de construcciones que admiten JavaScript y Flow React, lo que ayuda a que TypeScript funcione mejor con patrones de biblioteca de terceros.
Otro no ideal que encuentro es que los fragmentos profundizan el árbol de componentes, especialmente en los componentes de utilidad/envoltura (caso en cuestión: marcador de posición de reacción). Enviar a React.ReactElement
parece un mejor enfoque en este tipo de bibliotecas, pero prefiero no tener que enviar.
Intenté un enfoque para cambiar ese tipo, pero me quedé atascado con la verificación de tipos JSX usando un componente funcional del nuevo tipo. Todavía tengo la sucursal, podría haber jurado que hice un PR pidiendo ayuda, no puedo volver a encontrarla...
De acuerdo, si type necesita no permitir matrices de nodos, no significa que deba no permitir ReactText
, ReactPortal
, boolean
, null
y undefined
también lo que hace el uso de ReactElement
.
¿Cuál es la razón de prohibir estos tipos adicionales?
Comentario más útil
Actualmente estoy envolviendo
children
enReact.Fragment
para evitar esto.