@types/react
e tive problemas.Definitions by:
em index.d.ts
) para que eles possam responder.Os seguintes componentes
const SFC: React.StatelessComponent = (props) => props.children;
class C extends React.Component {
render() {
return this.props.children;
}
}
dê os erros
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 se você envolver children
em um Element
.
Retornar children
é bastante comum ao fazer componentes Provider que apenas adicionam algo a context
.
Eu tentei as seguintes correções para 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;
mas recebi erros em todo o lugar ao tentar lint que não tenho certeza de como corrigir.
TypeScript compile error: JSX element type 'ReactNode' is not a constructor function for JSX elements.
Não, esta alteração está incorreta. Você não pode retornar vários elementos no React atualmente. Mesmo se você fizer isso em algum lugar, provavelmente está encapsulado em um único de alguma forma.
Apenas no React 16 com Fiber isso pode ser possível :)
não tenho certeza se eles mudaram o comportamento de reação, mas o autor redux/react mostrou a capacidade de retornar this.props.children para criar wrappers finos (apenas para adicionar childContext a elementos), como visto em https://egghead.io/lessons/ javascript-redux-passing-the-store-down-implicitly-via-context
O react-native permite que você retorne uma matriz de elementos JSX da renderização. uma solução é envolver o this.props.children
com React.Children.only(this.props.children)
e ele será lançado se houver mais de um único elemento como raiz
Certo, você pode usar React.Children.only
mas ambos ReactNode
E ReactElement
são valores válidos de this.props.children
.
const Title = props => <h1>{props.children}</h1>;
<Title>Woah</Title>
é um código React válido e razoável.
Você pode retornar uma matriz de elementos em react 16, mas o TS lança um erro porque acha que você não pode.
Edit: faça isso children: JSX.Element[];
para corrigi-lo
Da minha experiência até agora, parece que o ReactNode deve ser válido.
const Id: React.SFC<{}> = (props) => props.children
const App = ()= > <Id>This should work but instead fails</Id>
Existe alguma chance de isso se refletir em @types/react
?
Sem isso, não consigo digitar React children
Atualmente estou envolvendo children
em React.Fragment
para contornar isso.
Alguma atualização sobre ele?
Não tenho certeza se isso é mais ou menos correto do que envolver children
em um React.Fragment
, mas tive sorte em fazer
return (children as React.ReactElement);
return <>{foo(}</>;
noite toda. <>
é uma solução alternativa.
Isso está causando problemas para mim também.
Eu tenho um HOC que adiciona props a um determinado componente e estou tentando usá-lo com um componente funcional que possui return children;
. Só funciona se eu usar a solução alternativa return <>{children}</>;
.
Aqui está uma versão simplificada do 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} />
)
}
}
}
Aqui está uma versão simplificada do 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);
Estou tendo o erro a seguir:
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'.
Se eu adicionar um tipo de retorno de ReactElement | null
ao ExampleComponent, ele para de reclamar de passá-lo para o HOC, mas ainda apresenta erros onde estou retornando os filhos:
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'.
}
Tal como acontece com os outros aqui, se eu mudar para return <>{children}</>;
, funciona, mas parece nojento e desnecessário.
Eu tenho o mesmo problema _exato_ que @kyrstenkelly - Uma função HOC sendo passada React.FC
que renderiza seus filhos.
A correção <> children(...) </>
funciona, mas existe uma solução melhor ainda?
Também to com esse problema! Atualmente fazendo a sugestão de solução de encapsulamento com React.Fragment
Mesmo aqui
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>
)
};
Acredito que tentei tudo o que foi aconselhado aqui... :( Alguma pista?
A solução é que você precisa envolvê-lo em fragmento.
import React from 'react'
const Something: React.FC = ({ children }) => (
<> { children } </>
)
isso corrigirá o erro Type '({ children }: { children?: ReactNode; }) => ReactNode' is not assignable to type 'FunctionComponent
.
Se possível, gostaria de evitar fragmentos e fazer com que o sistema de tipos JSX suporte os mesmos tipos de construções que JavaScript e Flow React suportam, o que ajuda o TypeScript a funcionar melhor com padrões de biblioteca de terceiros.
Outro não ideal que acho é que os fragmentos aprofundem a árvore de componentes, especialmente em componentes utilitários/empacotadores (caso em questão: react-placeholder). Casting para um React.ReactElement
parece ser uma abordagem melhor neste tipo de biblioteca, mas eu prefiro não precisar lançar.
Eu tentei uma abordagem para alterar esse tipo, mas fiquei preso com a verificação de tipos JSX usando um componente funcional do novo tipo. Ainda tenho a filial, poderia jurar que fiz um PR pedindo ajuda, não consigo encontrá-la de volta...
Ok, se o tipo precisar proibir matrizes de nós, isso não significa que ele deve proibir ReactText
, ReactPortal
, boolean
, null
e undefined
também o que o uso de ReactElement
faz.
Qual o racional de proibir esses tipos adicionais?
Comentários muito úteis
Atualmente estou envolvendo
children
emReact.Fragment
para contornar isso.