O que significa o erro "tipo de elemento JSX '...' não possui nenhuma construção ou assinatura de chamada"?

157

Eu escrevi um código:

function renderGreeting(Elem: React.Component<any, any>) {
    return <span>Hello, <Elem />!</span>;
}

Estou recebendo um erro:

O tipo de elemento JSX Elemnão possui nenhuma assinatura de construção ou chamada

O que isso significa?

Ryan Cavanaugh
fonte

Respostas:

196

Essa é uma confusão entre construtores e instâncias .

Lembre-se de que quando você escreve um componente no React:

class Greeter extends React.Component<any, any> {
    render() {
        return <div>Hello, {this.props.whoToGreet}</div>;
    }
}

Você o usa desta maneira:

return <Greeter whoToGreet='world' />;

Você não o usa desta maneira:

let Greet = new Greeter();
return <Greet whoToGreet='world' />;

No primeiro exemplo, estamos divulgando Greetera função construtora do nosso componente. Esse é o uso correto. No segundo exemplo, estamos passando uma instância de Greeter. Isso está incorreto e falhará em tempo de execução com um erro como "Objeto não é uma função".


O problema com este código

function renderGreeting(Elem: React.Component<any, any>) {
    return <span>Hello, <Elem />!</span>;
}

é que está esperando uma instância de React.Component. O que você quer uma função que leva um construtor para React.Component:

function renderGreeting(Elem: new() => React.Component<any, any>) {
    return <span>Hello, <Elem />!</span>;
}

ou similarmente:

function renderGreeting(Elem: typeof React.Component) {
    return <span>Hello, <Elem />!</span>;
}
Ryan Cavanaugh
fonte
31
Como desta escrita, se você estiver usando @types/react-los é mais fácil de usarfunction RenderGreeting(Elem: React.ComponentType) { ... }
Jthorpe
Apenas curioso, como escrevemos function renderGreeting(Elem: typeof React.Component)no ES6?
Bruce Sun
Obrigado. Qual seria o caso se quisermos passar um componente funcional sem estado? Acho function renderGreeting (Elem: new() => React.SFC<any>){...}Se assim por que declarar o tipo de SFCs assim: const Hello:React.SFC<any> = (props) => <div>Hello World</div>, e não:const Hello: new() =>React.SFC<any> = (props) => <div>Hello World</div>
Ben Carp
1
@Jorpe seu comentário deve ser uma resposta e uma resposta aceita na IMO.
Tomáš Hübelbauer 19/02/19
export const BackNavigationTextWrapper = (WrappedComponent: typeof React.Component) => { const BackNavigationTextWrappedComponent = (props, { commonElements = {} }: any) => { return <WrappedComponent {...props} backLabel={commonElements.backLabel || 'Go back to reservation details'} /> }; BackNavigationTextWrappedComponent.type = WrappedComponent.type; return BackNavigationTextWrappedComponent; }; Estou recebendo um erro "A propriedade 'type' não existe no tipo 'typeof Component'".
Prakash P
60

Se você deseja obter uma classe de componente como parâmetro (versus uma instância), use React.ComponentClass:

function renderGreeting(Elem: React.ComponentClass<any>) {
    return <span>Hello, <Elem />!</span>;
}
Lucas
fonte
Agora, com componentes funcionais na mistura, você provavelmente deve usar o React.ComponentType<any>tipo para incluí-los.
Zack
34

Quando estou convertendo de JSX para TSX e mantemos algumas bibliotecas como js / jsx e convertemos outras para ts / tsx, quase sempre esqueço de alterar as instruções de importação de js / jsx nos arquivos TSX \ TS de

import * as ComponentName from "ComponentName";

para

import ComponentName from "ComponentName";

Se chamar um componente de estilo JSX (React.createClass) antigo do TSX, use

var ComponentName = require("ComponentName")

Michael
fonte
4
Eu acho que você quis dizer o contrário?
apieceofbart
5
Não é necessário alterar a instrução inport se você configurar o TypeScript (por exemplo, in tsconfig.json) para allowSyntheticDefaultImports. Veja: typescriptlang.org/docs/handbook/compiler-options.html e discussão aqui: blog.jonasbandi.net/2016/10/…
jbandi
11

Se você realmente não se importa com acessórios, o tipo mais amplo possível é React.ReactType.

Isso permitiria passar elementos dom nativos como string. React.ReactTypeabrange todos estes:

renderGreeting('button');
renderGreeting(() => 'Hello, World!');
renderGreeting(class Foo extends React.Component {
   render() {
      return 'Hello, World!'
   }
});
epsilon
fonte
8

Se você estiver usando material-ui , vá para a definição de tipo do componente, que está sendo sublinhada pelo TypeScript. Muito provavelmente você verá algo parecido com isto

export { default } from './ComponentName';

Você tem 2 opções para resolver o erro:

1.Add .defaultquando se utiliza o componente em JSX:

import ComponentName from './ComponentName'

const Component = () => <ComponentName.default />

2. Nomeie o componente que está sendo exportado como "padrão" ao importar:

import { default as ComponentName } from './ComponentName'

const Component = () => <ComponentName />

Dessa forma, você não precisa especificar .defaultsempre que usar o componente.

Eduard
fonte
1
Isso me ajudou a corrigir meu problema.
WhiteWalker
2

No meu caso, eu estava usando React.ReactNodecomo um tipo para um componente funcional em vez de React.FCtipo.

Neste componente para ser exato:

export const PropertiesList: React.FC = (props: any) => {
  const list:string[] = [
    ' Consequat Phasellus sollicitudin.',
    ' Consequat Phasellus sollicitudin.',
    '...'
  ]

  return (
    <List
      header={<ListHeader heading="Properties List" />}
      dataSource={list}
        renderItem={(listItem, index) =>
          <List.Item key={index}> {listItem } </List.Item>
      }
    />
  )
}

ArchNoob
fonte
2

Como o @Jthorpe aludiu, ComponentClasspermite apenas um Componentou PureComponentnão um FunctionComponent.

Se você tentar passar um FunctionComponent, datilografado lançará um erro semelhante a ...

Type '(props: myProps) => Element' provides no match for the signature 'new (props: myProps, context?: any): Component<myProps, any, any>'.

No entanto, usando em ComponentTypevez de ComponentClasspermitir os dois casos. De acordo com o arquivo de declaração de reação, o tipo é definido como ...

type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>
Nickofthyme
fonte
2

No meu caso, estava faltando newdentro da definição de tipo.

some-js-component.d.ts Arquivo:

import * as React from "react";

export default class SomeJSXComponent extends React.Component<any, any> {
    new (props: any, context?: any)
}

e dentro do tsxarquivo em que eu estava tentando importar o componente não digitado:

import SomeJSXComponent from 'some-js-component'

const NewComp = ({ asdf }: NewProps) => <SomeJSXComponent withProps={asdf} />
jmunsch
fonte
2

Ao declarar o componente React Class, use em React.ComponentClass vez de React.Componentcorrigir o erro ts.

snowyBunny
fonte
1

Você pode usar

function renderGreeting(props: {Elem: React.Component<any, any>}) {
    return <span>Hello, {props.Elem}!</span>;
}

No entanto, o seguinte funciona?

function renderGreeting(Elem: React.ComponentType) {
    const propsToPass = {one: 1, two: 2};

    return <span>Hello, <Elem {...propsToPass} />!</span>;
}
Mark Kalinovits
fonte