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

Rya*_*ugh 124 typescript reactjs material-ui

我写了一些代码:

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

我收到一个错误:

JSX元素类型Elem没有任何构造或调用签名

这是什么意思?

Rya*_*ugh 167

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

请记住,当您在React中编写组件时:

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

你这样使用它:

return <Greeter whoToGreet='world' />;
Run Code Online (Sandbox Code Playgroud)

不要这样使用它:

let Greet = new Greeter();
return <Greet whoToGreet='world' />;
Run Code Online (Sandbox Code Playgroud)

在第一个例子中,我们传递了组件Greeter构造函数.这是正确的用法.在第二个例子中,我们绕过一个实例Greeter.这是不正确的,并且会在运行时因"对象不是函数"之类的错误而失败.


这段代码的问题

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

是它的预期的情况下React.Component.你想要什么一个函数,构造函数React.Component:

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

或类似的:

function renderGreeting(Elem: typeof React.Component) {
    return <span>Hello, <Elem />!</span>;
}
Run Code Online (Sandbox Code Playgroud)

  • 在撰写本文时,如果你使用`@ types/react`它们最容易使用`函数RenderGreeting(Elem:React.ComponentType){...}` (23认同)
  • @Jthorpe 您的评论应该是该 IMO 的答案和被接受的评论。 (7认同)
  • 只是好奇,我们如何在 ES6 中编写 function renderGreeting(Elem: typeof React.Component) ? (2认同)

Niv*_*han 61

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

interface Props{
  GraphComp: React.ElementType
}

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

  return (
   <div> <GraphComp /> </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

  • 我在发送组件作为道具时使用 JSX.Element 。这有帮助 (2认同)

Luk*_*uke 56

如果要将组件类作为参数(与实例对比),请使用React.ComponentClass:

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

  • 现在混合了功能组件,您可能应该使用“React.ComponentType&lt;any&gt;”类型来包含它们。 (3认同)

Mic*_*ael 30

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

import * as ComponentName from "ComponentName";

import ComponentName from "ComponentName";

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

var ComponentName = require("ComponentName")

  • 如果将TypeScript(即`tsconfig.json`)配置为"allowSyntheticDefaultImports",则不需要更改inport语句.请参阅:https://www.typescriptlang.org/docs/handbook/compiler-options.html以及此处的讨论:http://blog.jonasbandi.net/2016/10/myth-of-superset.html#comment-2936077278 (5认同)
  • 我认为你的意思是相反? (4认同)

小智 25

以下对我有用:https : //github.com/microsoft/TypeScript/issues/28631#issuecomment-472606019我通过执行以下操作来修复它:

const Component = (isFoo ? FooComponent : BarComponent) as React.ElementType
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,它对我有很大帮助。&lt;3 (2认同)
  • @AdriánRodriguez,首先像 Warao 描述的那样添加三元组件: const Component = (isFoo ? FooComponent : BarComponent) as React.ElementType ,然后当您使用组件 Component 时只需像往常一样传递 props : &lt;Component name='John'age= {55} /&gt; (2认同)

Zee*_*mad 20

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

import React from 'react';

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

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

  return <span>Hello, <Element />!</span>;
}
Run Code Online (Sandbox Code Playgroud)


Zar*_*old 16

看起来现在有一个特殊的新 TypeScript 类型来解决这个问题的需要:JSXElementConstructor。如果您让某人将构造函数传递给未知的 ReactElement 而不是该 ReactElement 的实例,那么这是要传递的正确类型。

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

这相当于上面选择的正确答案,因为:<Elem />在 JSX 中使用(又名用尖括号包裹大写变量)相当于使用关键字调用 JSX 元素的构造函数new


lel*_*tai 12

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

我正在使用的库如下所示:

export { default as Arc } from './shapes/Arc';
Run Code Online (Sandbox Code Playgroud)

我错误地导入了它,这导致了错误:

import Arc from "@visx/shape";
Run Code Online (Sandbox Code Playgroud)

应该是什么

import { Arc } from "@visx/shape";
Run Code Online (Sandbox Code Playgroud)


Edu*_*ard 10

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

export { default } from './ComponentName';
Run Code Online (Sandbox Code Playgroud)

您有 2 个选项可以解决该错误:

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

import ComponentName from './ComponentName'

const Component = () => <ComponentName.default />
Run Code Online (Sandbox Code Playgroud)

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

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

const Component = () => <ComponentName />
Run Code Online (Sandbox Code Playgroud)

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


eps*_*lon 8

如果你真的不关心道具那么最广泛的类型是React.ReactType.

这将允许将本机dom元素作为字符串传递.React.ReactType涵盖所有这些:

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

  • React.ReactType 现已弃用,应改用 React.ElementType。 (2认同)

Nic*_*yme 7

正如@Jthorpe 所暗示的,ComponentClass只允许ComponentPureComponent不允许FunctionComponent.

如果您尝试传递 a FunctionComponent,打字稿将抛出类似于...

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

但是,通过使用ComponentType而不是ComponentClass允许两种情况。根据反应声明文件,类型定义为...

type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>
Run Code Online (Sandbox Code Playgroud)


sno*_*nny 5

在声明 React Class 组件时,使用React.ComponentClass 而不是React.Componentthen 将修复 ts 错误。