Verwenden der JS React-Komponente in TypeScript: Der JSX-Elementtyp 'MyComponent' ist keine Konstruktorfunktion für JSX-Elemente

8

Ich arbeite mit einem JavaScript-Legacy-Projekt, das das React-Framework verwendet. Wir haben dort eine React-Komponente definiert, die ich in einem völlig anderen TypeScript React-Projekt wiederverwenden möchte.

Die JS React-Komponente ist in der Datei controls.jsx definiert und sieht folgendermaßen aus:

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

In meinem TypeScript React-Projekt versuche ich es so zu verwenden:

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

aber ich bekomme folgenden Fehler: Geben Sie hier die Bildbeschreibung ein

Fehlermeldungen sagen:

Der JSX-Elementtyp 'MyComponent' ist keine Konstruktorfunktion für JSX-Elemente. Beim Typ 'MyComponent' fehlen die folgenden Eigenschaften vom Typ 'ElementClass': context, setState, forceUpdate, props und 2 more.ts (2605) Die JSX-Elementklasse unterstützt keine Attribute, da sie keine 'props'-Eigenschaft.ts enthält (2607)

Ich habe die Lösung bereits mit einer in dieser Frage beschriebenen benutzerdefinierten Typisierungsdatei ausprobiert , aber sie ändert nichts.

Ich verstehe, dass die JS-Komponente einige stark typisierte Eigenschaften hat, die von TypeScript benötigt werden, aber in meiner tsconfig.json habe ich die allowJs auf true gesetzt :

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

also hoffte ich, dass es funktionieren sollte ...

Danke für Ihre Hilfe

Dawid Sibiński
quelle
Haben Sie diese Lösungen ausprobiert -> github.com/DefinitelyTyped/DefinitelyTyped/issues/21242 ?
Mihai T
Ich habe es versucht, aber nichts hilft ... Ich benutze kein Garn, so wenige davon waren irrelevant. Die anderen helfen überhaupt nicht ...
Dawid Sibiński
Es funktioniert gut für mich ohne Probleme. Ich habe gerade eine Typoskript-App erstellt und die Datei controls.jsx bei src hinzugefügt.
Deep
Hmm ... also ist es vielleicht eine Frage einiger npm-Pakete? Oder ihre Versionen? Könnten Sie Ihre tsconfig.json, package.json und vielleicht webpack.config.js teilen?
Dawid Sibiński
Das hört sich sehr danach an, als hätten Sie nicht übereinstimmende React- und React-Dom-Typisierungen. Können Sie Ihre package-lock & package.json teilen? Aufgrund der Länge müssen Sie möglicherweise die Paketsperre auf den Pastebin / Gist setzen.
Dan Pantry

Antworten:

1

Sie sollten sich allowSyntheticDefaultImportsan wenden , trueda React keine Standardeinstellungen exportiert.

(Quelle: 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"
  ]
}

Außerdem sollten Sie die Form für Komponentenstützen hinzufügen. Zum Beispiel in Ihrem Code:

export class MyComponent extends React.Component<{ message: string }> { ...
Langer Nguyen
quelle
1
Vielen Dank für Ihre Antwort. Einstellung allowSyntheticDefaultImportszu trueÄnderungen nichts, ich bin immer noch den gleichen Fehler. Ich kann keine Form für Komponenten-Requisiten hinzufügen, da diese in einer .jsx-Datei definiert ist und die folgende Fehlermeldung angezeigt wird: "'Typargumente' können nur in einer .ts-Datei verwendet werden. Tts (8011)"
Dawid Sibiński
0

Hier sind die Konfigurationen für Ihre Referenz, die ich in meiner Beispielanwendung verwende.

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

Ich habe kein Webpack verwendet.

Tief
quelle
Selbst wenn ich Ihre Konfigurationen nehme, hilft es nicht ...: /
Dawid Sibiński
0

So wie ich das sehe, haben Sie zwei Möglichkeiten:

  1. Sie können eine Deklarationsdatei im selben Verzeichnis wie angegeben controls.jsxangeben controls.t.ds.

Diese Option hat zwei Möglichkeiten. Am einfachsten ist es, eine Funktion mit dem Namen zu exportieren MyComponent:

export function MyComponent(): any;

Die zweite besteht darin, eine Variable zu exportieren, die die Klassenstruktur einer Komponente nachahmt:

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. Ihre zweite Option besteht darin, Ihre Komponente zu importieren und mit einer Typdefinition erneut zu exportieren. Diese Datei würde irgendwo im Projekt enthalten sein:
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};

Und dann würden Sie in Ihrer Datei, die MyComponentSie verwenden möchten, diese stattdessen aus dieser neuen Datei importieren.

Dies sind alles wirklich grobe Lösungen, aber ich glaube, es ist die einzige Lösung, da Sie mit TypeScript kein Modul definieren können, das relativ zu Ihrem Projekt ist:

declare module "../project/Controls" {

}

Hoffe das hilft.

Kyle
quelle
Ich habe versucht , die Option 2 , und ich erklärte , diese zusätzliche Datei, zusätzlich ein Hinzufügen messagevon stringTyp zu der Komponente ( MyComponent extends React.Component<{ message: string }>und VS - Code gibt mir keine Fehler , wenn diese Komponente aus der neuen Datei zu importieren. Aber ich bin immer noch einen Compiler - Fehler bekommen in der neuen Datei:Module not found: Error: Can't resolve '../../../../JS_TS_Project/Scripts/application/controls'
Dawid Sibiński
@ DawidSibiński Welchen Packager verwenden Sie? Metro, Babel, WebPack?
Kyle
Ich benutze Webpack
Dawid Sibiński
@ DawidSibiński Ich glaube, Sie müssen Webpack anweisen, das JS_TS_Project in die Include-Auflösung aufzunehmen. Siehe diese SO-Antwort: stackoverflow.com/a/54257787/701263
Kyle
Danke @Kyle, aber ich kann es immer noch nicht zum Laufen bringen ... Ich habe ein bisschen aufgegeben, weil ich endlich eine separate TS-Komponente verwendet habe. Das Thema bleibt jedoch weiterhin offen und interessant. Selbst wenn eine dieser Lösungen funktioniert hat, sind beide Module / Projekte immer noch eng miteinander verbunden und weit entfernt von einer zuverlässigen und wiederverwendbaren Lösung.
Dawid Sibiński