我写了一些代码:
function renderGreeting(Elem: React.Component<any, any>) {
return <span>Hello, <Elem />!</span>;
}
我收到错误:
JSX元素类型
Elem
没有任何构造或调用签名
这是什么意思?
答案 0 :(得分:143)
这是构造函数和实例之间的混淆。
请记住,在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
的实例。这是不正确的,并且在运行时会因为错误而失败,例如&#34;对象不是函数&#34;。
此代码的问题
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>;
}
答案 1 :(得分:48)
如果要将组件类作为参数(与实例对比),请使用React.ComponentClass
:
function renderGreeting(Elem: React.ComponentClass<any>) {
return <span>Hello, <Elem />!</span>;
}
答案 2 :(得分:26)
当我从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")
答案 3 :(得分:10)
以下内容对我有用:https://github.com/microsoft/TypeScript/issues/28631#issuecomment-472606019我通过执行以下操作对其进行了修复:
const Component = (isFoo ? FooComponent : BarComponent) as React.ElementType
答案 4 :(得分:7)
如果您真的不在乎道具,则可能的最大类型是React.ReactType
。
这将允许将本地dom元素作为字符串传递。 React.ReactType
涵盖了所有这些内容:
renderGreeting('button');
renderGreeting(() => 'Hello, World!');
renderGreeting(class Foo extends React.Component {
render() {
return 'Hello, World!'
}
});
答案 5 :(得分:4)
正如@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
,您可以允许两种情况。根据react声明文件,类型定义为...
type ComponentType<P = {}> = ComponentClass<P, any> | FunctionComponent<P>
答案 6 :(得分:4)
这是我搜索错误时的第一个结果,所以我想分享我在特定情况下的解决方案:
我使用的库如下所示:
export { default as Arc } from './shapes/Arc';
我错误地导入它,导致错误:
import Arc from "@visx/shape";
应该是什么
import { Arc } from "@visx/shape";
答案 7 :(得分:3)
如果要将功能组件作为道具传递给其他组件,请使用以下命令:
import React from 'react';
type RenderGreetingProps = {
element: React.FunctionComponent<any>
};
function RenderGreeting(props: RenderGreetingProps) {
const {element: Element} = props;
return <span>Hello, <Element />!</span>;
}
答案 8 :(得分:2)
如果您使用的是 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
。
答案 9 :(得分:1)
就我而言,我在类型定义内缺少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'
...inside render()
return (
<React.Fragment>
<SomeJSXComponent withProps={asdf} />
</React.Fragment>
);
答案 10 :(得分: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>;
}
答案 11 :(得分:0)
在声明React类组件时,使用React.ComponentClass
代替React.Component
,它将解决ts错误。
答案 12 :(得分:0)
就我而言,我使用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>
}
/>
)
}
答案 13 :(得分:0)
我在导出组件之前通过使用 类型断言 解决了该问题。 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>
答案 14 :(得分:0)
以下是使用 TSX 的示例:
const SomeMadeComponent = () => (
<div>
<p>Some text</p>
</div>
);
您可以像使用普通组件一样使用它:
<SomeMadeComponent />
答案 15 :(得分:0)
看起来现在有一个特殊的新 TypeScript 类型来解决这个问题的需要:JSXElementConstructor
。如果您让某人将构造函数传递给未知的 ReactElement 而不是该 ReactElement 的实例,则这是要传递的正确类型。
const renderGreeting = (Elem: JSXElementConstructor<any, any>) => {
return <span>Hello, <Elem />!</span>;
}
这相当于上面选择的正确答案,因为使用 <Elem />
相当于使用 new
关键字调用 JSX 元素的构造函数。