注释从这开始~

总览

当咱们试图将元素或react组件作为属性传递给另一个组件,然而属性的类型申明谬误时,会产生"JSX element type does not have any construct or call signatures"谬误。为了解决该谬误,能够应用React.ElementType类型。

这里有个例子来展现谬误是如何产生的。

// App.tsximport React from 'react';interface Props {  comp: JSX.Element;}const Wrapper: React.FunctionComponent<Props> = props => {  const {comp: Comp} = props;  // ⛔️ JSX element type 'Comp' does not have any construct or call signatures.ts(2604)  return (    <div>      <Comp name="James" />    </div>  );};const App: React.FunctionComponent = () => {  const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;  return (    <div>      <Wrapper comp={heading} />    </div>  );};export default App;

咱们尝试将一个React组件作为属性传递给Wrapper组件,但咱们将该React组件的类型申明为JSX.Element

React.ElementType

为了解决该谬误,将属性的类型申明为React.ElementType

// App.tsximport React from 'react';interface Props {  comp: React.ElementType; // ️ type it as React.ElementType}const Wrapper: React.FunctionComponent<Props> = props => {  // ️ component names must start with capital letter  const {comp: Comp} = props;  return (    <div>      <Comp name="James" />    </div>  );};const App: React.FunctionComponent = () => {  // ️ takes a name prop  const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;  return (    <div>      <Wrapper comp={heading} />    </div>  );};export default App;
请留神,React.ElementType能够为元素冀望的属性类型传递一个泛型。

在这个例子中,咱们必须传递给它一个具备字符串类型的name属性的对象,因为那是heading组件接管的属性。

// App.tsximport React from 'react';interface Props {  // ✅ explicitly type props comp takes  comp: React.ElementType<{name: string}>;}const Wrapper: React.FunctionComponent<Props> = props => {  // ️ component names must start with capital letter  const {comp: Comp} = props;  return (    <div>      <Comp name="James" />    </div>  );};const App: React.FunctionComponent = () => {  const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;  return (    <div>      <Wrapper comp={heading} />    </div>  );};export default App;

当初咱们显式地申明了元素在应用时所承受的comp属性的类型。这有助于咱们在向组件传递属性时利用IDE的主动实现性能。

咱们也能够应用React.ComponentType,但这样咱们就须要对属性申明类型。

// App.tsximport React from 'react';interface Props {  // ️ now using React.ComponentType ️  comp: React.ComponentType<{name: string}>;}const Wrapper: React.FunctionComponent<Props> = props => {  // ️ component names must start with capital letter  const {comp: Comp} = props;  return (    <div>      <Comp name="James" />    </div>  );};const App: React.FunctionComponent = () => {  const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;  return (    <div>      <Wrapper comp={heading} />    </div>  );};export default App;

React.ComponentType 中的泛型不能默认为any类型,因而咱们须要显示地申明属性的类型。

传递JSX元素

如果你须要将JSX元素作为属性传递给组件,并且不是一个真正的组件,那么应用JSX.Element类型就是正确的。

// App.tsximport React from 'react';interface Props {  // ️ using JSX.Element type  comp: JSX.Element;}const Wrapper: React.FunctionComponent<Props> = props => {  const {comp: Comp} = props;  // ️ use as {Comp}  return <div>{Comp}</div>;};const App: React.FunctionComponent = () => {  const Heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;  // ️ we are passing an actual JSX element  // because we didn't pass it as comp={Heading}  return (    <div>      <Wrapper comp={<Heading name="James" />} />    </div>  );};export default App;

咱们将comp属性的类型申明为JSX.Element,因为咱们传递了一个真正的JSX元素(不是组件)到Wrapper组件上。

咱们传递了一个JSX元素,是因为咱们将comp={<Heading />}作为属性进行传递,而不是comp={(props) => <h2>Hello world</h2>}

须要留神的是,在第一种状况下,咱们传递的是一个JSX元素属性。而在第二种状况下,咱们传递的是一个返回JSX元素的函数(一个性能组件)。

在Wrapper组件中,咱们不应尝试应用JSX元素作为组件。比如说,不要这么写<Comp />,而要这么写{Comp}

咱们没有传递一个真正的组件作为属性,咱们传递的是一个JSX元素,所以它不应该作为一个组件应用。

更新类型包

如果后面的倡议都没有帮忙,试着通过运行以下命令来更新你的React类型的版本。

# ️ with NPMnpm install react@latest react-dom@latestnpm install --save-dev @types/react@latest @types/react-dom@latest# ----------------------------------------------# ️ with YARNyarn add react@latest react-dom@latestyarn add @types/react@latest @types/react-dom@latest --dev