簡體   English   中英

在 TypeScript 中使用 JS React 組件:JSX 元素類型“MyComponent”不是 JSX 元素的構造函數

[英]Using JS React component in TypeScript: JSX element type 'MyComponent' is not a constructor function for JSX elements

我正在處理一個使用 React 框架的 JavaScript 遺留項目。 我們定義了一些 React 組件,我想在一個完全不同的 TypeScript React 項目中重用它們。

JS React 組件在 control.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”類型中的以下屬性:context、setState、forceUpdate、props 和另外 2 個。ts(2605) JSX 元素類不支持屬性,因為它沒有“props”屬性。ts (2607)

我已經嘗試過使用問題中描述的自定義類型文件的解決方案,但它沒有任何改變。

我知道 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"
  ]
}

所以我希望它應該工作......

謝謝你的幫助

您應該將allowSyntheticDefaultImportstrue因為 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 }> { ...

以下是我在示例應用程序中使用的配置供您參考。

配置文件

{
  "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"
  ]
}

包.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。

在我看來,你有兩個選擇:

  1. 您可以在與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;
}
  1. 您的第二個選擇是導入您的組件並使用類型定義重新導出它。 此文件將包含在項目中的某處:
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" {

}

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM