在 TypeScript 中使用 JS React 组件:JSX 元素类型“MyComponent”不是 JSX 元素的构造函数
Posted
技术标签:
【中文标题】在 TypeScript 中使用 JS React 组件:JSX 元素类型“MyComponent”不是 JSX 元素的构造函数【英文标题】:Using JS React component in TypeScript: JSX element type 'MyComponent' is not a constructor function for JSX elements 【发布时间】:2020-04-09 17:46:57 【问题描述】:我正在处理一个使用 React 框架的 javascript 遗留项目。我们已经定义了一些 React 组件,我想在一个完全不同的 TypeScript React 项目中重用它们。
JS React 组件在 controls.jsx 文件中定义,如下所示:
export class MyComponent extends React.Component
render()
return <h1>Hi from MyComponent! Message provided: this.props.message</h1>;
在我的 TypeScript React 项目中,我尝试这样使用它:
import * as React from "react";
import * as ReactDOM from "react-dom";
import MyComponent from "../JavaScriptProject/controls";
ReactDOM.render(
<MyComponent message="some nice message"/>,
document.getElementById("documents-tree")
);
但我收到以下错误:
错误信息说:
JSX 元素类型“MyComponent”不是 JSX 的构造函数 元素。类型“MyComponent”缺少以下属性 来自“ElementClass”类型:上下文、setState、forceUpdate、props 和 2 more.ts(2605) JSX 元素类不支持属性,因为它 没有“道具”属性。ts(2607)
我已经尝试了this 问题中描述的自定义类型文件的解决方案,但它没有任何改变。
我了解 JS 组件缺少 TypeScript 所需的一些强类型属性,但在我的 tsconfig.json 中,我将 allowJs 设置为 true:
"compilerOptions":
"allowJs": true,
"baseUrl": ".",
"experimentalDecorators": true,
"jsx": "react",
"noEmitOnError": true,
"outDir": "lib",
"sourceMap": true,
"target": "es5",
"lib": [
"es2015",
"dom"
]
,
"exclude": [
"node_modules",
"dist",
"lib",
"lib-amd"
]
所以我希望它应该工作......
感谢您的帮助
【问题讨论】:
你尝试过这些解决方案吗 -> github.com/DefinitelyTyped/DefinitelyTyped/issues/21242 ? 我试过了,但没有任何帮助......我不使用纱线,所以它们中的少数是无关紧要的。其他人根本没有帮助...... 它对我来说很好用,没有任何问题。我刚刚创建了一个打字稿应用程序并在 src 添加了 controls.jsx 文件。 嗯......所以也许这是一些 npm 包的问题?还是他们的版本?你能分享你的 tsconfig.json、package.json 和 webpack.config.js 吗? 这听起来很像你的 react 和 react-dom 类型不匹配。你能分享你的 package-lock 和 package.json 吗?由于它的长度,您可能需要在 pastebin/gist 上放置 package-lock。 【参考方案1】:你应该把 allowSyntheticDefaultImports
变成 true
因为 React 不导出默认值。
(来源:https://github.com/facebook/react/blob/master/packages/react/index.js)
"compilerOptions":
"allowJs": true,
"baseUrl": ".",
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true, // turn on allowSyntheticDefaultImports
"jsx": "react",
"noEmitOnError": true,
"outDir": "lib",
"sourceMap": true,
"target": "es5",
"lib": [
"es2015",
"dom"
]
,
"exclude": [
"node_modules",
"dist",
"lib",
"lib-amd"
]
此外,您应该为组件道具添加形状。例如,在您的代码中:
export class MyComponent extends React.Component< message: string > ...
【讨论】:
感谢您的回答。将allowSyntheticDefaultImports
设置为true
没有任何改变,我仍然遇到同样的错误。我无法为组件道具添加形状,因为它是在 .jsx 文件中定义的,并且出现以下错误:“'type arguments' can only be used in a .ts file.ts(8011)”【参考方案2】:
以下是我在示例应用程序中使用的配置供您参考。
tsconfig.json
"compilerOptions":
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
,
"include": [
"src"
]
package.json
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies":
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.4.0",
"@testing-library/user-event": "^7.1.2",
"@types/jest": "^24.0.23",
"@types/node": "^12.12.18",
"@types/react": "^16.9.16",
"@types/react-dom": "^16.9.4",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-scripts": "3.3.0",
"typescript": "^3.7.3"
,
"scripts":
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
,
"eslintConfig":
"extends": "react-app"
,
"browserslist":
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
我没用过 webpack。
【讨论】:
即使我接受你的配置也无济于事......:/【参考方案3】:在我看来,你有两个选择:
-
您可以在与
controls.jsx
相同的目录中提供一个名为controls.t.ds
的声明文件。
此选项有两种处理方式。最简单的就是导出一个名为MyComponent
的函数:
export function MyComponent(): any;
第二种是导出一个模仿组件类结构的变量:
interface Element
render(): any;
context: any;
setState: any;
forceUpdate: any;
props: any;
state: any;
refs: any;
interface MyComponent extends Element
export var MyComponent:
new(): MyComponent;
-
您的第二个选项是导入您的组件并使用类型定义重新导出它。该文件将包含在项目中的某处:
import React from 'react';
import MyComponent as _MyComponent from '../project-a/Controls';
interface MyComponent extends React.Component
const MyComponent = (_MyComponent as any) as
new(): MyComponent;
;
export MyComponent;
然后在你想要使用MyComponent
的文件中,你可以从那个新文件中导入它。
这些都是非常糟糕的解决方案,但我相信这是唯一的解决方案,因为 TypeScript 不允许您定义与您的项目相关的模块:
declare module "../project/Controls"
希望这会有所帮助。
【讨论】:
我尝试了选项 2,并声明了这个额外的文件,另外添加了一个string
类型的 message
到组件(MyComponent extends React.Component< message: string >
和 VS Code 在导入时没有给我任何错误这个组件来自新文件。但是,我仍然在新文件中收到编译错误:Module not found: Error: Can't resolve '../../../../JS_TS_Project/Scripts/application/controls'
@DawidSibiński 您使用的是什么打包程序? Metro、babel、WebPack?
我正在使用 webpack
@DawidSibiński 我相信你必须告诉 Webpack 将 JS_TS_Project 包含在它的包含分辨率中。看到这个答案:***.com/a/54257787/701263
感谢@Kyle,但仍然无法让它工作......我放弃了一点,因为最后,我使用了一个单独的 TS 组件。然而,这个问题仍然是开放和有趣的。即使其中一个解决方案有效,这仍然是两个模块/项目的紧密耦合,远非可靠且可重用的解决方案。以上是关于在 TypeScript 中使用 JS React 组件:JSX 元素类型“MyComponent”不是 JSX 元素的构造函数的主要内容,如果未能解决你的问题,请参考以下文章
如何在带有 typescript 项目的 react js 中使用 .env 文件?
如何在 React 应用程序的 typescript 文件中导入 js 模块(使用绝对路径)?
在 Typescript、Webpack、React 项目中使用 css-in-js 时没有重载匹配此调用错误
在 TypeScript 中使用 NextJS 设置 Jest + React 测试库 -- 设置 upp jest.config.js 时出错
在 TypeScript 中使用 JS React 组件:JSX 元素类型“MyComponent”不是 JSX 元素的构造函数