正文从这开始~

总览

当我们试图将元素或react组件作为属性传递给另一个组件,但是属性的类型声明错误时,会产生"JSX element type does not have any construct or call signatures"错误。为了解决该错误,可以使用React.ElementType类型。

这里有个例子来展示错误是如何发生的。

  1. // App.tsx
  2. import React from 'react';
  3. interface Props {
  4. comp: JSX.Element;
  5. }
  6. const Wrapper: React.FunctionComponent<Props> = props => {
  7. const {comp: Comp} = props;
  8. // ️ JSX element type 'Comp' does not have any construct or call signatures.ts(2604)
  9. return (
  10. <div>
  11. <Comp name="James" />
  12. </div>
  13. );
  14. };
  15. const App: React.FunctionComponent = () => {
  16. const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;
  17. return (
  18. <div>
  19. <Wrapper comp={heading} />
  20. </div>
  21. );
  22. };
  23. export default App;

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

React.ElementType

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

  1. // App.tsx
  2. import React from 'react';
  3. interface Props {
  4. comp: React.ElementType; // ️ type it as React.ElementType
  5. }
  6. const Wrapper: React.FunctionComponent<Props> = props => {
  7. // ️ component names must start with capital letter
  8. const {comp: Comp} = props;
  9. return (
  10. <div>
  11. <Comp name="James" />
  12. </div>
  13. );
  14. };
  15. const App: React.FunctionComponent = () => {
  16. // ️ takes a name prop
  17. const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;
  18. return (
  19. <div>
  20. <Wrapper comp={heading} />
  21. </div>
  22. );
  23. };
  24. export default App;

请注意,React.ElementType可以为元素期望的属性类型传递一个泛型。

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

  1. // App.tsx
  2. import React from 'react';
  3. interface Props {
  4. // explicitly type props comp takes
  5. comp: React.ElementType<{name: string}>;
  6. }
  7. const Wrapper: React.FunctionComponent<Props> = props => {
  8. // ️ component names must start with capital letter
  9. const {comp: Comp} = props;
  10. return (
  11. <div>
  12. <Comp name="James" />
  13. </div>
  14. );
  15. };
  16. const App: React.FunctionComponent = () => {
  17. const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;
  18. return (
  19. <div>
  20. <Wrapper comp={heading} />
  21. </div>
  22. );
  23. };
  24. export default App;

现在我们显式地声明了元素在使用时所接受的comp属性的类型。这有助于我们在向组件传递属性时利用IDE的自动完成功能。

我们也可以使用React.ComponentType,但这样我们就需要对属性声明类型。

  1. // App.tsx
  2. import React from 'react';
  3. interface Props {
  4. // ️ now using React.ComponentType ️
  5. comp: React.ComponentType<{name: string}>;
  6. }
  7. const Wrapper: React.FunctionComponent<Props> = props => {
  8. // ️ component names must start with capital letter
  9. const {comp: Comp} = props;
  10. return (
  11. <div>
  12. <Comp name="James" />
  13. </div>
  14. );
  15. };
  16. const App: React.FunctionComponent = () => {
  17. const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;
  18. return (
  19. <div>
  20. <Wrapper comp={heading} />
  21. </div>
  22. );
  23. };
  24. export default App;

React.ComponentType 中的泛型不能默认为any类型,因此我们需要显示地声明属性的类型。

传递JSX元素

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

  1. // App.tsx
  2. import React from 'react';
  3. interface Props {
  4. // ️ using JSX.Element type
  5. comp: JSX.Element;
  6. }
  7. const Wrapper: React.FunctionComponent<Props> = props => {
  8. const {comp: Comp} = props;
  9. // ️ use as {Comp}
  10. return <div>{Comp}</div>;
  11. };
  12. const App: React.FunctionComponent = () => {
  13. const Heading = ({name}: {name: string}) => <h2>Hello {name}</h2>;
  14. // ️ we are passing an actual JSX element
  15. // because we didn't pass it as comp={Heading}
  16. return (
  17. <div>
  18. <Wrapper comp={<Heading name="James" />} />
  19. </div>
  20. );
  21. };
  22. 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类型的版本。

  1. # ️ with NPM
  2. npm install react@latest react-dom@latest
  3. npm install --save-dev @types/react@latest @types/react-dom@latest
  4. # ----------------------------------------------
  5. # ️ with YARN
  6. yarn add react@latest react-dom@latest
  7. yarn add @types/react@latest @types/react-dom@latest --dev

React报错之JSX element type does not have any construct or call signatures的更多相关文章

  1. React报错之组件不能作为JSX组件使用

    正文从这开始~ 总览 组件不能作为JSX组件使用,出现该错误有多个原因: 返回JSX元素数组,而不是单个元素. 从组件中返回JSX元素或者null以外的任何值. 使用过时的React类型声明. 返回单 ...

  2. react 报错的堆栈处理

    react报错 Warning: You cannot PUSH the same path using hash history 在Link上使用replace 原文地址https://reactt ...

  3. go语言byte类型报错cannot use "c" (type string) as type byte in assignment

    练习Go修改字符串的时候遇到这个问题:cannot use "c" (type string) as type byte in assignment,代码如下: package m ...

  4. 报错: Access restriction: The type JPEGImageEncoder is not accessible due to restriction on required library

    报错: Access restriction:The type JPEGCodec is not accessible due to restriction on required library C ...

  5. Linux mount挂载磁盘报错 mount: wrong fs type, bad option, bad superblock on /dev/vdb

    Linux mount挂载磁盘报错  mount: wrong fs type, bad option, bad superblock on /dev/vdb Linux挂载磁盘报如下错误: moun ...

  6. React报错之Type '() => JSX.Element[]' is not assignable to type FunctionComponent

    正文从这开始~ 总览 当我们尝试从函数组件中返回元素组成的数组时,会产生"Type '() => JSX.Element[]' is not assignable to type Fu ...

  7. React报错之Property 'X' does not exist on type 'HTMLElement'

    正文从这开始~ 总览 在React中,当我们试图访问类型为HTMLElement 的元素上不存在的属性时,就会发生Property 'X' does not exist on type 'HTMLEl ...

  8. React报错之Property 'value' does not exist on type 'HTMLElement'

    正文从这开始~ 总览 当我们试图访问一个类型为HTMLElement的元素上的value属性时,会产生"Property 'value' does not exist on type 'HT ...

  9. React报错之Cannot find name

    正文从这开始~ .tsx扩展名 为了在React TypeScript中解决Cannot find name报错,我们需要在使用JSX文件时使用.tsx扩展名,在你的tsconfig.json文件中把 ...

随机推荐

  1. JVM学习笔记-从底层了解程序运行(二)

    解决JVM运行中的问题 一个案例理解常用工具 测试代码: /** * 从数据库中读取信用数据,套用模型,并把结果进行记录和传输 */ public class T15_FullGC_Problem01 ...

  2. Vuex的各个模块封装

    一.各个模块的作用: state 用来数据共享数据存储 mutation 用来注册改变数据状态(同步) getters 用来对共享数据进行过滤并计数操作 action 解决异步改变共享数据(异步) 二 ...

  3. 基于Vue.js的Web视频播放器插件vue-vam-video@1.3.6 正式发布

    前言 今日正式发布一款基于Vue.js的Web视频播放器插件.可配置,操作灵活.跟我一起来体验吧! 线上地址体验 基于vue3.0和vue-vam-video,我开发了一款在线视频播放器. 网址: h ...

  4. Linux系统安全配置

    1.物理安全 硬件服务器,关闭从CD/DVD等这些方面的软启动方式.同时也可以设置BIOS密码,并且要有限制访问的策略与各类流程管控. 还可以禁用USB设备来达到安全的目的: centos7x 安装d ...

  5. UiPath录制器的介绍和使用

    一.录制器(Recording)的介绍 录制器是UiPath Studio的重要组成部分,可以帮助您在自动化业务流程时节省大量时间.此功能使您可以轻松地在屏幕上捕获用户的动作并将其转换为序列. 二.录 ...

  6. 【python基础】第10回 周总结

    路径 可以简单的理解为路径就是某个事物所在的具体位置(坐标) 1.相对路径:必须有一个参考系,就是相对于自己的目标文件的位置. 2.绝对路劲:不需要有参考系,是指文件在硬盘上真正存在的路径. 计算机五 ...

  7. java 改变图片的DPI

    代码如下: public class test01 { private static int DPI = 300; public static void main(String[] args) { S ...

  8. NC24325 [USACO 2012 Mar S]Flowerpot

    NC24325 [USACO 2012 Mar S]Flowerpot 题目 题目描述 Farmer John has been having trouble making his plants gr ...

  9. 生成RSA密钥的方法[转载]

    openssl genrsa -des3 -out privkey.pem 2048 这个命令会生成一个2048位的密钥,同时有一个des3方法加密的密码,如果你不想要每次都输入密码,可以改成(测试常 ...

  10. Cisco Packet Tracer Student(思科网络模拟器)模拟集线器和嗅探攻击

    一.集线器简介 集线器是局域网内的基础设备,工作于OSI中的物理层,作用是将接收的信号进行放大再传输,集线器是纯硬件设施,集线器开发之初就没考虑过软件层面的操作,所以不具备像路由器.交换机等设备那样具 ...