我写了一些代码:

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

我得到一个错误:

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

这是什么意思?


当前回答

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

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

这等价于上面选择的正确答案,因为:在JSX中使用<Elem />(也就是用尖括号将大写变量括起来)等效于使用new关键字调用JSX元素的构造函数。

其他回答

正如@Jthorpe所提到的,ComponentClass只允许Component或PureComponent,而不允许FunctionComponent。

如果你试图传递一个FunctionComponent, typescript将抛出一个类似于…

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

但是,通过使用ComponentType而不是ComponentClass,可以同时满足这两种情况。根据react声明文件,类型定义为…

type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>

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

这将允许将原生dom元素作为字符串传递。反应。ElementType涵盖了所有这些:

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

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

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

这等价于上面选择的正确答案,因为:在JSX中使用<Elem />(也就是用尖括号将大写变量括起来)等效于使用new关键字调用JSX元素的构造函数。

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

export { default } from './ComponentName';

你有两个选项来解决这个错误:

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

import ComponentName from './ComponentName'

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

2.在导入时,将组件重命名为“default”:

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

const Component = () => <ComponentName />

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

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

我正在使用的库是这样的:

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

我导入错误,导致错误:

import Arc from "@visx/shape";

它应该是

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