共计 3381 个字符,预计需要花费 9 分钟才能阅读完成。
注释从这开始~
总览
当咱们试图将元素或 react 组件作为属性传递给另一个组件,然而属性的类型申明谬误时,会产生 ”JSX element type does not have any construct or call signatures” 谬误。为了解决该谬误,能够应用 React.ElementType
类型。
这里有个例子来展现谬误是如何产生的。
// App.tsx
import 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.tsx
import 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.tsx
import 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.tsx
import 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.tsx
import 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 NPM
npm install react@latest react-dom@latest
npm install --save-dev @types/react@latest @types/react-dom@latest
# ----------------------------------------------
# 👇️ with YARN
yarn add react@latest react-dom@latest
yarn add @types/react@latest @types/react-dom@latest --dev