Sử dụng thành phần JS React trong TypeScript: Kiểu phần tử JSX 'MyComponent' không phải là hàm xây dựng cho các phần tử JSX


8

Tôi đang làm việc với một dự án kế thừa JavaScript sử dụng khung React. Chúng tôi có một số thành phần React được xác định mà tôi muốn sử dụng lại trong một dự án TypeScript React hoàn toàn khác.

Thành phần JS React được định nghĩa trong tệp controls.jsx và trông như sau:

export class MyComponent extends React.Component {
  render() {
    return <h1>Hi from MyComponent! Message provided: {this.props.message}</h1>;
  }
}

Trong dự án TypeScript React của tôi, tôi đang cố gắng sử dụng nó như thế:

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")
);

nhưng tôi nhận được lỗi sau: nhập mô tả hình ảnh ở đây

Thông báo lỗi cho biết:

Kiểu phần tử JSX 'MyComponent' không phải là hàm xây dựng cho các phần tử JSX. Loại 'MyComponent' thiếu các thuộc tính sau từ loại 'ElementClass': bối cảnh, setState, forceUpdate, props và 2 more.ts (2605) Lớp phần tử JSX không hỗ trợ các thuộc tính vì nó không có thuộc tính 'props'. (2607)

Tôi đã thử giải pháp với tệp đánh máy tùy chỉnh được mô tả trong câu hỏi này , nhưng nó không thay đổi gì.

Tôi hiểu rằng thành phần JS có một số thuộc tính được gõ mạnh theo yêu cầu của TypeScript, nhưng trong tsconfig.json, tôi có các allowJ được đặt thành 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"
  ]
}

Vì vậy, tôi hy vọng nó sẽ hoạt động ...

Cảm ơn bạn đã giúp đỡ


Bạn đã thử các giải pháp này -> github.com/DefiniteTyped/DefiniteTyped/issues/21242 ?
Mihai T

Tôi đã thử, nhưng không có gì giúp được ... Tôi không sử dụng sợi nên rất ít trong số chúng không liên quan. Những người khác không giúp đỡ gì cả ...
Dawid Sibiński

Nó hoạt động tốt cho tôi mà không có bất kỳ vấn đề. tôi vừa tạo một ứng dụng bản thảo và thêm tệp controls.jsx tại src.
Sâu

Hmm ... vậy có lẽ đó là vấn đề của một số gói npm? Hoặc phiên bản của họ? Bạn có thể chia sẻ tsconfig.json, pack.json và có thể là webpack.config.js không?
Dawid Sibiński

điều này nghe có vẻ giống như bạn đã đánh máy không phù hợp và kiểu chữ Reac-dom. bạn có thể chia sẻ gói-lock & pack.json của bạn không? bạn có thể cần đặt khóa gói trên pastebin / gist do độ dài của nó.
Dan Pantry

Câu trả lời:


1

Bạn nên chuyển allowSyntheticDefaultImportssang truevì React không xuất mặc định.

(nguồn: 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"
  ]
}

Ngoài ra, bạn nên thêm hình dạng cho đạo cụ thành phần. Ví dụ: trong mã của bạn:

export class MyComponent extends React.Component<{ message: string }> { ...

1
Cảm ơn đã trả lời. Thiết allowSyntheticDefaultImportsđể truecó gì thay đổi, tôi vẫn nhận được lỗi tương tự. Tôi không thể thêm hình dạng cho các đạo cụ thành phần, vì nó được xác định trong tệp .jsx và tôi đang gặp lỗi sau: "'đối số loại' chỉ có thể được sử dụng trong tệp .ts.ts (8011)"
Dawid Sibiński

0

Dưới đây là các cấu hình để bạn tham khảo mà tôi đang sử dụng trong ứng dụng mẫu của mình.

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

pack.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"
    ]
  }
}

Tôi chưa sử dụng webpack.


Ngay cả khi tôi lấy cấu hình của bạn, nó cũng không giúp ích gì ...: /
Dawid Sibiński

0

Theo cách tôi thấy, bạn có hai lựa chọn:

  1. Bạn có thể cung cấp một tệp khai báo trong cùng thư mục như controls.jsxđược đặt tên controls.t.ds.

Tùy chọn này có hai cách để đi về nó. Đơn giản nhất là xuất một hàm với tên MyComponent:

export function MyComponent(): any;

Thứ hai là xuất một biến bắt chước cấu trúc lớp của một thành phần:

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. Tùy chọn thứ hai của bạn là nhập thành phần của bạn và tái xuất nó với định nghĩa kiểu. Tập tin này sẽ được bao gồm ở đâu đó trong dự án:
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};

Và sau đó trong tệp của bạn muốn sử dụng MyComponent, bạn sẽ nhập nó từ tệp mới đó.

Đây đều là những giải pháp thực sự thô thiển, nhưng tôi tin rằng đó là giải pháp duy nhất vì TypeScript không cho phép bạn xác định một mô-đun có liên quan đến dự án của bạn:

declare module "../project/Controls" {

}

Hi vọng điêu nay co ich.


Tôi đã thử các phương án 2 và tôi tuyên bố tập thêm này, thêm bổ sung một messagesố stringloại với thành phần ( MyComponent extends React.Component<{ message: string }>và VS Mã không cho tôi bất kỳ sai sót khi nhập thành phần này từ các tập tin mới. Tuy nhiên, tôi vẫn nhận được một lỗi biên dịch trong tập tin mới:Module not found: Error: Can't resolve '../../../../JS_TS_Project/Scripts/application/controls'
Dawid Sibiński

@ DawidSibiński Bạn đang sử dụng packager nào? Metro, babel, WebPack?
Kyle

Tôi đang sử dụng gói web
Dawid Sibiński

@ DawidSibiński Tôi tin rằng bạn sẽ phải nói với Webpack để bao gồm JS_TS_Project trong đó bao gồm độ phân giải. Xem câu trả lời SO này: stackoverflow.com/a/54257787/701263
Kyle

Cảm ơn @Kyle, nhưng vẫn không thể làm cho nó hoạt động ... Tôi đã từ bỏ một chút, vì cuối cùng, tôi đã sử dụng một thành phần TS riêng biệt. Tuy nhiên, vấn đề vẫn còn mở và thú vị. Ngay cả khi một trong những giải pháp này hoạt động, đây vẫn là kết hợp chặt chẽ cả hai mô-đun / dự án và khác xa với một giải pháp đáng tin cậy và có thể sử dụng lại.
Dawid Sibiński
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.