ReactJS und Typescript: bezieht sich auf einen Wert, wird hier jedoch als Typ verwendet (TS2749)
Ich programmiere eine ReactJS-Klasse mit TypeScript und Material-UI in einer .tsx-Datei. In einer meiner benutzerdefinierten Komponenten möchte ich eine Referenz zu einer der Komponenten erstellen, die ich in meiner benutzerdefinierten Komponente verwende.
export class MyTextField extends React.Component<MyProps, MyState> {
private refTextField: React.RefObject<TextField>;
constructor(props: MyProps) {
super(props);
this.refTextField = React.createRef();
}
render(): JSX.Element {
const { id, label, value: defaultValue } = this.props;
const { value } = this.state;
const element = (
<TextField ref={this.refTextField} id={id} label={label} defaultValue={defaultValue} value={value} />
);
return element;
}
}
Während der Kompilierung erhalte ich einen Fehler bei der Deklaration meiner Referenz:
'TextField' bezieht sich auf einen Wert, wird hier jedoch als Typ verwendet. TS2749
Ich habe versucht, "typeof TextField" in meiner Deklaration zu verwenden, aber ich bekomme eine andere Meldung, wenn ich die ref-Eigenschaft in meinem Render-Methodenaufruf setze:
Typ 'RefObject<(props: TextFieldProps) => Element>' ist nicht zuweisbar zu Typ '((instance: HTMLDivElement | null) => void) | RefObject | null | undefined'. Typ 'RefObject<(props: TextFieldProps) => Element>' ist nicht zuweisbar zu Typ 'RefObject'. Typ '(props: TextFieldProps) => Element' fehlt die folgenden Eigenschaften vom Typ 'HTMLDivElement': align, addEventListener, removeEventListener, accessKey und 238 weitere. TS2322
Irgendwelche Ideen? Vielen Dank
Antwort #1
Stellen Sie sicher, dass Sie sich in einer .tsx-Datei und nicht in einer .ts-Datei befinden
Antwort #2
ändere die .ts-Datei zu .tsx
In meinem Fall funktioniert es
Antwort #3
Also bin ich in meinem Code schon mehrmals auf dieses Problem gestoßen, aber ich habe den Grund, warum das passiert, erst heute herausgefunden.
TL;DR: In deinem Fall musst du einfach InstanceType<typeof TextField> anstelle von TextField schreiben.
Wenn du eine Klasse in TypeScript erstellst, bezieht sich der Name dieser Klasse sowohl auf den Instanztyp als auch auf den JavaScript-Klassenwert. Wenn du diese Klasse als Typ referenzierst, erkennt TypeScript das automatisch als den Instanztyp dieser Klasse. Und wenn du diese Klasse zur Laufzeit referenzierst, wird sie einfach im JavaScript-Sinn verwendet. Und bis jetzt ist alles prima.
class MyClass {}
let abc: MyClass; // ts recognizes as instance type
abc = new MyClass(); // completely fine, used here as the javascript value
Das eigentliche Problem entsteht jedoch, wenn Sie die Klasse aus einem Modul dynamisch exportieren. Wenn Sie die Klasse auf bestimmte Arten exportieren, kann TypeScript nur den JavaScript-Wert der Klasse exportieren und nicht den Typ. Wenn Sie sie also in einem anderen Modul importieren und versuchen, sie als Typ zu referenzieren, erhalten Sie TS2749.
let intervariable = class MyClass{}
export const MyClass = intervariable; // TypeScript does not export type here.
import {MyClass} from './myclass';
let abc: MyClass; // TypeScript error TS2749
Wenn dies passiert, besonders wenn es außerhalb Ihrer Kontrolle liegt, war meine Lösung, um den Instanztyp zu erhalten, einfach InstanceType und typeof zu verwenden:
import {MyClass} from './myclass';
let abc: InstanceType<typeof MyClass>; // no error
// the rest...
Der typeof-Operator liefert Ihnen den Klassentyp-Konstruktor für einen Klassenwert, und der generische Typ InstanceType liefert Ihnen den Instanztyp, den Sie möchten.
Antwort #4
Ändern Sie zuerst den Dateityp .tsx
dann drücke F1 und tippe "Fenster neu laden"
:)
Antwort #5
Das hätte ein Kommentar sein sollen, aber ich habe nicht genug Reputation. Ich wollte mitteilen, dass eine saubere Möglichkeit, die von der akzeptierten Antwort empfohlene Lösung zu verwenden, darin besteht, einen Typalias mit demselben Namen zu deklarieren (es verursacht keinen Konflikt). Dann können Sie Ihren Typ auf die gleiche Weise verwenden, wie Sie normalerweise einen Instanztyp verwenden würden.
Zur Ergänzung des Beispiels:
import {MyClass} from './myclass';
type MyClass = InstanceType<typeof MyClass>;
let abc: MyClass; // still no error!
Bearbeiten: Ein Typ-Import scheint auch zu funktionieren und sieht sauberer aus:
import type {MyClass} from './myclass';
Der Vorbehalt bei der import type-Methode ist, dass Sie sie nicht als Wert verwenden können (z. B. um new MyClass(...) zu konstruieren).
