Che cosa significa l'errore "Tipo di elemento JSX '...' non ha costrutti o firme di chiamata"?


158

Ho scritto del codice:

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

Ricevo un errore:

Il tipo di elemento JSX Elemnon ha costrutti o firme di chiamata

Cosa significa?

Risposte:


196

Questa è una confusione tra costruttori ed istanze .

Ricorda che quando scrivi un componente in React:

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

Lo usi in questo modo:

return <Greeter whoToGreet='world' />;

Non lo usi in questo modo:

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

Nel primo esempio, stiamo passando in giro Greeter, la funzione di costruzione per il nostro componente. Questo è l'uso corretto. Nel secondo esempio, stiamo passando a un'istanza di Greeter. Non è corretto e non funzionerà in fase di esecuzione con un errore del tipo "L'oggetto non è una funzione".


Il problema con questo codice

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

è che si aspetta un'istanza di React.Component. Cosa vuoi una funzione che richiede un costruttore per React.Component:

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

o similmente:

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

31
Al momento della stesura di questo documento, se li stai usando @types/reactè più facile da usarefunction RenderGreeting(Elem: React.ComponentType) { ... }
Jthorpe,

Solo curioso, come scriviamo function renderGreeting(Elem: typeof React.Component)in ES6?
Bruce Sun,

Grazie. Cosa accadrebbe se volessimo passare un componente funzionale apolide? Immagino function renderGreeting (Elem: new() => React.SFC<any>){...}se sì perché dichiariamo il tipo di SFC come questo:, const Hello:React.SFC<any> = (props) => <div>Hello World</div>e non:const Hello: new() =>React.SFC<any> = (props) => <div>Hello World</div>
Ben Carp

1
@Jthorpe il tuo commento dovrebbe essere una risposta e accettata a quell'IMO.
Tomáš Hübelbauer,

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; }; Ricevo un errore "Il tipo di proprietà" non esiste sul tipo "tipo di componente" ".
Prakash P

60

Se si desidera prendere una classe componente come parametro (rispetto a un'istanza), utilizzare React.ComponentClass:

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

Ora con componenti funzionali nel mix, probabilmente dovresti usare il React.ComponentType<any>tipo invece di includerli.
Zack

34

Quando sto convertendo da JSX a TSX e manteniamo alcune librerie come js / jsx e ne convertiamo altre in ts / tsx quasi sempre dimentico di cambiare le istruzioni di importazione js / jsx nei file TSX \ TS da

import * as ComponentName from "ComponentName";

per

import ComponentName from "ComponentName";

Se si chiama un vecchio componente di stile JSX (React.createClass) da TSX, utilizzare

var ComponentName = require("ComponentName")


4
Penso che volevi dire il contrario?
apieceofbart

5
La modifica dell'istruzione inport non è necessaria se si configura TypeScript (ovvero in tsconfig.json) su allowSyntheticDefaultImports. Vedi: typescriptlang.org/docs/handbook/compiler-options.html e discussione qui: blog.jonasbandi.net/2016/10/10
jbandi

11

Se davvero non ti importa degli oggetti di scena, allora il tipo più ampio possibile è React.ReactType.

Ciò consentirebbe il passaggio di elementi dom nativi come stringa. React.ReactTypecopre tutti questi:

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

8

Se stai usando material-ui , vai alla definizione del tipo del componente, che è sottolineato da TypeScript. Molto probabilmente vedrai qualcosa del genere

export { default } from './ComponentName';

Hai 2 opzioni per risolvere l'errore:

1.Aggiungi .defaultquando usi il componente in JSX:

import ComponentName from './ComponentName'

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

2. Rinominare il componente, che viene esportato come "predefinito", durante l'importazione:

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

const Component = () => <ComponentName />

In questo modo non è necessario specificare .defaultogni volta che si utilizza il componente.


1
Questo mi ha aiutato a risolvere il mio problema.
WhiteWalker,


2

Nel mio caso, stavo usando React.ReactNodecome tipo per un componente funzionale anziché React.FCtipo.

In questo componente per l'esattezza:

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>
      }
    />
  )
}


2

Come accennato a @Jthorpe, ComponentClassconsente solo Componento PureComponentma non a FunctionComponent.

Se si tenta di passare un FunctionComponent, dattiloscritto genererà un errore simile a ...

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

Tuttavia, utilizzando ComponentTypepiuttosto che ComponentClassconsentire per entrambi i casi. Per il file di dichiarazione di reazione il tipo è definito come ...

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

2

Nel mio caso mi mancava newnella definizione del tipo.

some-js-component.d.ts file:

import * as React from "react";

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

e all'interno del tsxfile in cui stavo cercando di importare il componente non tipizzato:

import SomeJSXComponent from 'some-js-component'

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

2

Quando si dichiara il componente React Class, utilizzare React.ComponentClass invece di React.Componentallora risolverà l'errore ts.


1

Puoi usare

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

Tuttavia, funziona quanto segue?

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

    return <span>Hello, <Elem {...propsToPass} />!</span>;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.