错误“JSX 元素类型'...'没有任何构造或调用签名”是什么意思?

问题描述 投票:0回答:18

我写了一些代码:

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

我收到一个错误:

JSX 元素类型

Elem
没有任何构造或调用签名

什么意思?

reactjs typescript
18个回答
362
投票

这是构造函数实例之间的混淆。

请记住,当您在 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
instance
。这是不正确的,并且会在运行时失败并出现类似“对象不是函数”的错误。


这段代码的问题

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

是它期待React.Component

instance
。你想要的是一个函数,它需要 a constructor for
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>;
}

90
投票

如果您想将组件类作为参数(相对于实例),请使用

React.ComponentClass

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

59
投票

以下对我有用:https://github.com/microsoft/TypeScript/issues/28631#issuecomment-472606019我通过这样做来修复它:

const Component = (isFoo ? FooComponent : BarComponent) as React.ElementType

45
投票

当我从 JSX 转换为 TSX 并且我们将一些库保留为 js/jsx 并将其他库转换为 ts/tsx 时,我几乎总是忘记更改 TSX\TS 文件中的 js/jsx 导入语句从

import * as ComponentName from "ComponentName";

import ComponentName from "ComponentName";

如果从 TSX 调用旧的 JSX (React.createClass) 样式组件,则使用

var ComponentName = require("ComponentName")


38
投票

如果您将功能组件作为道具传递给另一个组件,请使用以下内容:

import React from 'react';

type RenderGreetingProps = {
  element: React.FunctionComponent<any>
};

function RenderGreeting(props: RenderGreetingProps) {
  const {element: Element} = props;

  return <span>Hello, <Element />!</span>;
}

36
投票

如果您正在使用 Functional Component 并将组件作为 prop 传递,对我来说,解决方案是将 React.ReactNode 更改为 React.ElementType

interface Props{
  GraphComp: React.ElementType
}

const GraphCard:React.FC<Props> = (props) => {
  const { GraphComp } = props;

  return (
   <div> <GraphComp /> </div>
  )
}

20
投票

如果你真的不关心道具那么最广泛的可能类型是

React.ElementType
.

这将允许将原生 dom 元素作为字符串传递。

React.ElementType
涵盖所有这些:

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

15
投票

看起来现在有一个特殊的新 TypeScript 类型可以解决这个问题的需要:

JSXElementConstructor
。如果您让某人将构造函数传递给未知的 ReactElement 而不是该 ReactElement 的实例,这是要传递的正确类型。

const renderGreeting = (Elem: JSXElementConstructor<any>) => {
    return <span>Hello, <Elem />!</span>;
}

这等同于上面选择的正确答案,因为:在 JSX 中使用

<Elem />
(又名用尖括号包裹大写变量)等同于使用
new
关键字调用 JSX 元素的构造函数。


14
投票

如果您使用的是material-ui,请转到组件的类型定义,它由 TypeScript 加下划线。你很可能会看到这样的东西

export { default } from './ComponentName';

您有 2 个选项来解决错误:

1.在JSX中使用组件时添加

.default

import ComponentName from './ComponentName'

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

2.导入时重命名导出为“默认”的组件:

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

const Component = () => <ComponentName />

这样就不需要每次使用组件时都指定

.default


10
投票

正如@Jthorpe 所暗示的,

ComponentClass
只允许
Component
PureComponent
但不允许
FunctionComponent
.

如果你试图传递一个

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>

7
投票

这是我搜索错误时的第一个结果,所以我想在我的特定情况下分享解决方案:

我正在使用的图书馆看起来像这样:

export { default as Arc } from './shapes/Arc';

我导入错误,导致错误:

import Arc from "@visx/shape";

应该是

import { Arc } from "@visx/shape";

5
投票

在声明 React 类组件时,使用

React.ComponentClass
而不是
React.Component
然后它将修复 ts 错误。


4
投票

在我的例子中,我使用

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


3
投票
import React from 'react';

function MyComponent (
  WrappedComponent: React.FunctionComponent | React.ComponentClass
) {
  return (
    <Wrapper>
      <WrappedComponent />
    </Wrapper>
  );
}

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

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

-1
投票

我在导出组件之前使用 Type Assertions 解决了这个问题。 TypeScript 在使用 redux 'compose' 组合后无法识别因此我将道具类型分为 IParentProps 和 IProps 并在进行类型断言时使用 IParentProps

import { compose } from 'react-redux'
import HOC1 from 'HOCs/HOC1'
import HOC2 from 'HOCs/HOC2'

type IParentProps = {}
type IProps = {}

const Component: React.FC<IProps & IParentProps> = React.memo((props) => {

      return <SomeComponent {...props}/>

})

return compose(HOC1,HOC2)(Component) as React.FunctionComponent<IParentProps>

-6
投票

是语法的原因

这里有一个使用 TSX 的例子:

const SomeMadeComponent = (props: { someText: string }) => {
  const { someText} = props;
  return (
    <div>
      <p>{someText}</p>
    </div>
  );
};

你像普通组件一样使用它:

<SomeMadeComponent someText='Place your text here' />

© www.soinside.com 2019 - 2024. All rights reserved.