Що означає помилка "Тип елемента 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
@Jthorpe ваш коментар повинен відповісти і прийнято в цьому ІМО.
Томаш Хюбельбауер

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; }; Я отримую помилку "Властивості" тип "не існує для типу" typeof Компонент "".
Пракаш П

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. Дивіться: typecriptlang.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';

У вас є два варіанти вирішення помилки:

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


2

Як нагадав @Jthorpe, ComponentClassдозволяє лише те, чи Componentні, PureComponentале не FunctionComponent.

Якщо ви спробуєте передати A FunctionComponent, typecript видасть помилку, схожу на ...

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>

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

2

При оголошенні компонента React Class використовуйте React.ComponentClass замість React.Componentцього він виправить помилку ts.


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>;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.