Co oznacza błąd „Typ elementu JSX„… ”nie ma żadnej konstrukcji ani sygnatury wywołania”?

158

Napisałem kod:

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

Otrzymuję błąd:

Typ elementu JSX Elemnie ma żadnych konstrukcji ani sygnatur wywołań

Co to znaczy?

Ryan Cavanaugh
źródło

Odpowiedzi:

196

Jest to zamieszanie między konstruktorami a instancjami .

Pamiętaj, że pisząc komponent w Reakcie:

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

Używasz tego w ten sposób:

return <Greeter whoToGreet='world' />;

Państwo nie używać go w ten sposób:

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

W pierwszym przykładzie, jesteśmy przechodząc wokół Greeter, w funkcji konstruktora dla naszego komponentu. To prawidłowe użycie. W drugim przykładzie, jesteśmy przechodząc wokół jest wystąpienie o Greeter. To jest niepoprawne i zakończy się niepowodzeniem w czasie wykonywania z błędem typu „Obiekt nie jest funkcją”.


Problem z tym kodem

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

jest to, że spodziewa się wystąpienie o React.Component. Co chcesz funkcję, która pobiera konstruktora dla React.Component:

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

lub podobnie:

function renderGreeting(Elem: typeof React.Component) {
    return <span>Hello, <Elem />!</span>;
}
Ryan Cavanaugh
źródło
31
W chwili pisania tego tekstu, jeśli @types/reactich używasz , najłatwiej jest z nich korzystaćfunction RenderGreeting(Elem: React.ComponentType) { ... }
Jthorpe
Ciekawe, jak piszemy function renderGreeting(Elem: typeof React.Component)w ES6?
Bruce Sun,
Dzięki. Co by się stało, gdybyśmy chcieli przekazać bezstanowy komponent funkcjonalny? Wydaje mi się, że function renderGreeting (Elem: new() => React.SFC<any>){...}jeśli tak, to dlaczego deklarujemy typ KŁŻ w ten sposób: const Hello:React.SFC<any> = (props) => <div>Hello World</div>a nie:const Hello: new() =>React.SFC<any> = (props) => <div>Hello World</div>
Ben Carp,
1
@Jthorpe Twój komentarz powinien zawierać odpowiedź i zaakceptowany w tej 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; }; Otrzymuję błąd „Typ właściwości” nie istnieje w typie „Typ składnika”.
Prakash P
60

Jeśli chcesz wziąć klasę komponentu jako parametr (a nie instancję), użyj React.ComponentClass:

function renderGreeting(Elem: React.ComponentClass<any>) {
    return <span>Hello, <Elem />!</span>;
}
Łukasz
źródło
Teraz, gdy składniki funkcjonalne są w mieszance, prawdopodobnie powinieneś użyć React.ComponentType<any>typu zamiast uwzględniać je.
Zack
34

Kiedy konwertuję z JSX na TSX i zachowujemy niektóre biblioteki jako js / jsx, a inne konwertujemy na ts / tsx, prawie zawsze zapominam o zmianie instrukcji importu js / jsx w plikach TSX \ TS z

import * as ComponentName from "ComponentName";

do

import ComponentName from "ComponentName";

Jeśli wywołujesz stary komponent w stylu JSX (React.createClass) z TSX, użyj

var ComponentName = require("ComponentName")

Michael
źródło
4
Myślę, że miałeś na myśli odwrotnie?
apieceofbart
5
Zmiana instrukcji inport nie jest konieczna, jeśli skonfigurujesz TypeScript (tj. In tsconfig.json) na allowSyntheticDefaultImports. Zobacz: typescriptlang.org/docs/handbook/compiler-options.html i dyskusję tutaj: blog.jonasbandi.net/2016/10/...
jbandi
11

Jeśli naprawdę nie obchodzą cię rekwizyty, to najszerszy z możliwych jest React.ReactType.

Umożliwiłoby to przekazywanie natywnych elementów dom jako ciągów. React.ReactTypeobejmuje wszystkie te:

renderGreeting('button');
renderGreeting(() => 'Hello, World!');
renderGreeting(class Foo extends React.Component {
   render() {
      return 'Hello, World!'
   }
});
epsilon
źródło
8

Jeśli używasz material-ui , przejdź do definicji typu komponentu, która jest podkreślana przez TypeScript. Najprawdopodobniej zobaczysz coś takiego

export { default } from './ComponentName';

Masz dwie możliwości rozwiązania tego błędu:

1. Dodaj .defaultpodczas korzystania z komponentu w JSX:

import ComponentName from './ComponentName'

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

2. Zmień nazwę eksportowanego komponentu na „domyślną” podczas importowania:

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

const Component = () => <ComponentName />

W ten sposób nie musisz określać za .defaultkażdym razem, gdy używasz komponentu.

Eduard
źródło
1
Pomogło mi to w rozwiązaniu problemu.
WhiteWalker
2

W moim przypadku używałem React.ReactNodejako typu dla komponentu funkcjonalnego zamiast React.FCtypu.

W tym komponencie, aby być dokładnym:

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
źródło
2

Jak wspomniał @Jthorpe, ComponentClasszezwala tylko Componentlub PureComponentale nie FunctionComponent.

Jeśli spróbujesz przekazać a FunctionComponent, maszynopis zwróci błąd podobny do ...

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

Jednak używając ComponentTypezamiast ComponentClasszezwalać w obu przypadkach. W pliku deklaracji reakcji typ jest zdefiniowany jako ...

type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>
Nickofthyme
źródło
2

W moim przypadku brakowało mi neww definicji typu.

some-js-component.d.ts plik:

import * as React from "react";

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

i wewnątrz tsxpliku, w którym starałem się importować bez typu komponent:

import SomeJSXComponent from 'some-js-component'

const NewComp = ({ asdf }: NewProps) => <SomeJSXComponent withProps={asdf} />
jmunsch
źródło
2

Deklarując komponent klasy React, użyj React.ComponentClass zamiast React.Componenttego, naprawi to błąd ts.

snowyBunny
źródło
1

Możesz użyć

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

Jednak czy poniższe rozwiązania działają?

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

    return <span>Hello, <Elem {...propsToPass} />!</span>;
}
Mark Kalinovits
źródło