Was bedeutet der Fehler "JSX-Elementtyp '...' hat keine Konstrukt- oder Aufrufsignaturen"?

156

Ich habe Code geschrieben:

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

Ich erhalte eine Fehlermeldung:

Der JSX-Elementtyp Elemhat keine Konstrukt- oder Aufrufsignaturen

Was heißt das?

Ryan Cavanaugh
quelle

Antworten:

195

Dies ist eine Verwechslung zwischen Konstruktoren und Instanzen .

Denken Sie daran, wenn Sie eine Komponente in React schreiben:

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

Sie verwenden es so:

return <Greeter whoToGreet='world' />;

Sie verwenden es nicht so:

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

Im ersten Beispiel geben wir Greeterdie Konstruktorfunktion für unsere Komponente weiter. Das ist die richtige Verwendung. Im zweiten Beispiel geben wir eine Instanz von weiter Greeter. Das ist falsch und schlägt zur Laufzeit mit einem Fehler wie "Objekt ist keine Funktion" fehl.


Das Problem mit diesem Code

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

ist, dass es eine Instanz von erwartet React.Component. Was möchten Sie eine Funktion, die einen Konstruktor benötigt für React.Component:

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

oder ähnlich:

function renderGreeting(Elem: typeof React.Component) {
    return <span>Hello, <Elem />!</span>;
}
Ryan Cavanaugh
quelle
31
Zum @types/reactfunction RenderGreeting(Elem: React.ComponentType) { ... }
jetzigen Zeitpunkt ist
Nur neugierig, wie schreiben wir function renderGreeting(Elem: typeof React.Component)in ES6?
Bruce Sun
Vielen Dank. Was wäre der Fall, wenn wir eine zustandslose Funktionskomponente übergeben möchten? Ich denke, function renderGreeting (Elem: new() => React.SFC<any>){...}wenn ja, warum deklarieren wir die Art der SFCs wie folgt: const Hello:React.SFC<any> = (props) => <div>Hello World</div>und nicht:const Hello: new() =>React.SFC<any> = (props) => <div>Hello World</div>
Ben Carp
1
@Jthorpe Ihr Kommentar sollte eine Antwort und eine akzeptierte bei dieser IMO sein.
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; }; Ich erhalte die Fehlermeldung "Eigenschaft 'Typ' existiert nicht für Typ 'Typ der Komponente'".
Prakash P
60

Wenn Sie eine Komponentenklasse als Parameter (gegenüber einer Instanz) verwenden möchten, verwenden Sie React.ComponentClass:

function renderGreeting(Elem: React.ComponentClass<any>) {
    return <span>Hello, <Elem />!</span>;
}
Luke
quelle
Jetzt mit funktionalen Komponenten in der Mischung sollten Sie wahrscheinlich den React.ComponentType<any>Typ verwenden, um sie einzuschließen.
Zack
34

Wenn ich von JSX nach TSX konvertiere und einige Bibliotheken als js / jsx behalten und andere nach ts / tsx konvertieren, vergesse ich fast immer, die Importanweisungen von js / jsx in den TSX \ TS-Dateien von zu ändern

import * as ComponentName from "ComponentName";

zu

import ComponentName from "ComponentName";

Wenn Sie eine alte JSX-Stilkomponente (React.createClass) von TSX aus aufrufen, verwenden Sie

var ComponentName = require("ComponentName")

Michael
quelle
4
Ich denke du meintest umgekehrt?
pro Stück Bart
5
Das Ändern der inport-Anweisung ist nicht erforderlich, wenn Sie TypeScript (dh in tsconfig.json) auf konfigurieren allowSyntheticDefaultImports. Siehe: typescriptlang.org/docs/handbook/compiler-options.html und Diskussion hier: blog.jonasbandi.net/2016/10/…
jbandi
11

Wenn Sie sich wirklich nicht für Requisiten interessieren, ist der größtmögliche Typ React.ReactType.

Dies würde die Übergabe nativer dom-Elemente als Zeichenfolge ermöglichen. React.ReactTypedeckt all dies ab:

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

Wenn Sie material-ui verwenden , wechseln Sie zur Typdefinition der Komponente, die von TypeScript unterstrichen wird. Höchstwahrscheinlich werden Sie so etwas sehen

export { default } from './ComponentName';

Sie haben zwei Möglichkeiten, um den Fehler zu beheben:

1. Fügen Sie .defaultbei Verwendung der Komponente in JSX Folgendes hinzu :

import ComponentName from './ComponentName'

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

2.Benennen Sie die Komponente, die exportiert wird, beim Importieren als "Standard" um:

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

const Component = () => <ComponentName />

Auf diese Weise müssen Sie nicht .defaultjedes Mal angeben, wenn Sie die Komponente verwenden.

Eduard
quelle
1
Dies half mir bei der Behebung meines Problems.
WhiteWalker
2

Wenn Sie die React-Klassenkomponente deklarieren, verwenden Sie React.ComponentClass stattdessen React.Component, um den ts-Fehler zu beheben.

snowyBunny
quelle
2

In meinem Fall habe ich React.ReactNodeanstelle eines React.FCTyps einen Typ für eine Funktionskomponente verwendet.

In dieser Komponente um genau zu sein:

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
quelle
2

Wie @Jthorpe angedeutet hat, ComponentClasserlaubt nur entweder Componentoder PureComponentaber nicht a FunctionComponent.

Wenn Sie versuchen, a zu übergeben FunctionComponent, gibt Typoskript einen Fehler aus, der ...

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

Verwenden Sie jedoch beide Fälle , ComponentTypeanstatt ComponentClasssie zuzulassen. In der React-Deklarationsdatei ist der Typ definiert als ...

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

In meinem Fall fehlte ich newin der Typdefinition.

some-js-component.d.ts Datei:

import * as React from "react";

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

und in der tsxDatei, in der ich versucht habe, die untypisierte Komponente zu importieren:

import SomeJSXComponent from 'some-js-component'

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

Sie können verwenden

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

Funktioniert jedoch Folgendes?

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

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