Что означает ошибка «тип элемента JSX«… »не имеет никакой конструкции или сигнатуры вызова»?

158

Я написал некоторый код:

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

Я получаю сообщение об ошибке:

Тип элемента JSX Elemне имеет никакой конструкции или сигнатуры вызовов

Что это означает?

Райан Кавано
источник

Ответы:

196

Это путаница между конструкторами и экземплярами .

Помните, что когда вы пишете компонент в React:

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

Вы используете это так:

return <Greeter whoToGreet='world' />;

Вы не используете это таким образом:

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

В первом примере, мы проходим вокруг Greeter, в функцию конструктора для нашего компонента. Это правильное использование. Во втором примере, мы проходим вокруг экземпляра из Greeter. Это неверно и приведет к ошибке во время выполнения с ошибкой типа «Объект не является функцией».


Проблема с этим кодом

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

является то , что он ожидает экземпляр из React.Component. То , что вы хотите функцию , которая принимает конструктор для React.Component:

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

или аналогично:

function renderGreeting(Elem: typeof React.Component) {
    return <span>Hello, <Elem />!</span>;
}
Райан Кавано
источник
31
На момент написания этой статьи, если вы используете @types/reactих, ее проще всего использоватьfunction RenderGreeting(Elem: React.ComponentType) { ... }
Jthorpe
Просто любопытно, как мы пишем function renderGreeting(Elem: typeof React.Component)в ES6?
Брюс Сан
Спасибо. Что будет, если мы хотим передать функциональный компонент без состояния? Я полагаю, function renderGreeting (Elem: new() => React.SFC<any>){...}если так, почему мы объявляем тип SFC следующим образом:, const Hello:React.SFC<any> = (props) => <div>Hello World</div>а не:const Hello: new() =>React.SFC<any> = (props) => <div>Hello World</div>
Бен Карп
1
@Jororpe Ваш комментарий должен быть ответом и принятым в этом IMO.
Томаш Хюбельбауэр
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; }; Я получаю сообщение об ошибке «Свойство« type »не существует для типа« typeof Component »».
Пракаш П
60

Если вы хотите взять класс компонента в качестве параметра (против экземпляра), используйте React.ComponentClass:

function renderGreeting(Elem: React.ComponentClass<any>) {
    return <span>Hello, <Elem />!</span>;
}
Люк
источник
Теперь с функциональными компонентами в смеси, вы, вероятно, должны использовать React.ComponentType<any>тип вместо того, чтобы включать их.
Зэк
34

Когда я конвертирую из JSX в TSX, и мы сохраняем некоторые библиотеки как js / jsx и конвертируем другие в ts / tsx, я почти всегда забываю изменить операторы импорта js / jsx в файлах TSX \ TS из

import * as ComponentName from "ComponentName";

в

import ComponentName from "ComponentName";

Если вызывается старый компонент стиля JSX (React.createClass) из TSX, используйте

var ComponentName = require("ComponentName")

Майкл
источник
4
Я думаю, что вы имели в виду наоборот?
apieceofbart
5
Изменение оператора ввода не требуется, если вы настраиваете TypeScript (т.е. в tsconfig.json) на allowSyntheticDefaultImports. См .: typescriptlang.org/docs/handbook/compiler-options.html и обсуждение здесь: blog.jonasbandi.net/2016/10/…
jbandi
11

Если вы действительно не заботитесь о реквизите, то самый широкий из возможных типов React.ReactType.

Это позволит передавать нативные элементы dom в виде строки. React.ReactTypeохватывает все это:

renderGreeting('button');
renderGreeting(() => 'Hello, World!');
renderGreeting(class Foo extends React.Component {
   render() {
      return 'Hello, World!'
   }
});
эпсилон
источник
8

Если вы используете Material-UI , перейдите к определению типа компонента, который подчеркивается TypeScript. Скорее всего, вы увидите что-то подобное

export { default } from './ComponentName';

У вас есть 2 варианта для устранения ошибки:

1.Добавить .defaultпри использовании компонента в JSX:

import ComponentName from './ComponentName'

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

2. Переименуйте компонент, который экспортируется как «по умолчанию», при импорте:

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

const Component = () => <ComponentName />

Таким образом, вам не нужно указывать .defaultкаждый раз, когда вы используете компонент.

Эдуард
источник
1
Это помогло мне исправить мою проблему.
WhiteWalker
2

В моем случае я использовал React.ReactNodeтип вместо функционального компонента React.FC.

В этом компоненте быть точным:

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
источник
2

Как намекал @Jthorpe, ComponentClassразрешает только Componentили нет, PureComponentно не FunctionComponent.

Если вы попытаетесь передать a FunctionComponent, машинопись выведет ошибку, похожую на ...

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

Тем не менее, используя, ComponentTypeа не ComponentClassвы допускаете в обоих случаях. В соответствии с файлом объявления реакции тип определяется как ...

type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>
Nickofthyme
источник
2

В моем случае я отсутствовал newвнутри определения типа.

some-js-component.d.ts файл:

import * as React from "react";

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

и внутри tsxфайла, где я пытался импортировать нетипизированный компонент:

import SomeJSXComponent from 'some-js-component'

const NewComp = ({ asdf }: NewProps) => <SomeJSXComponent withProps={asdf} />
jmunsch
источник
2

При объявлении компонента React Class используйте React.ComponentClass вместо React.Componentнего, чтобы исправить ошибку ts.

snowyBunny
источник
1

Ты можешь использовать

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

Однако работает ли следующее?

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

    return <span>Hello, <Elem {...propsToPass} />!</span>;
}
Марк Калиновиц
источник