Vyhledávání na webu

ReactJS a Typescript: odkazuje na hodnotu, ale zde je používáno jako typ (TS2749)


Kóduji třídu ReactJS s Typescriptem a Material-ui v souboru .tsx. V jedné z mých vlastních komponent chci vytvořit referenci na jednu z komponent, které používám ve své vlastní komponentě.

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;
  }
}

Během kompilace dostávám chybu při deklaraci mé reference:

'TextField' odkazuje na hodnotu, ale zde je použit jako typ. TS2749

Snažil jsem se dát "typeof TextField" do mé deklarace, ale mám jinou zprávu, když nastavím vlastnost ref ve svém renderu :

Typ 'RefObject<(props: TextFieldProps) => Element>' nelze přiřadit k typu '((instance: HTMLDivElement | null) => void) | RefObject | null | undefined'. Typ 'RefObject<(props: TextFieldProps) => Element>' nelze přiřadit k typu 'RefObject'. Typ '(props: TextFieldProps) => Element' postrádá následující vlastnosti typu 'HTMLDivElement': align, addEventListener, removeEventListener, accessKey a dalších 238 vlastností. TS2322

Máte nějaké nápady? Moc děkuji.

Odpověď č. 1

Ujistěte se, že jste v souboru .tsx a ne v souboru .ts

Odpověď č. 2

změnit soubor .ts na .tsx

v mém případě to funguje

Odpověď č. 3

Takže jsem se s tímto problémem v mém kódu setkal několikrát, ale důvod, proč se to děje, jsem zjistil až dnes.

Shrnutí: Ve vašem případě stačí napsat InstanceType<typeof TextField> místo TextField.

Když vytvoříte třídu v TypeScriptu, název této třídy odkazuje jak na typ instance, tak na hodnotu třídy v JavaScriptu. Pokud tuto třídu odkážete jako typ, TypeScript to automaticky rozpozná jako typ instance této třídy. A pokud tuto třídu odkážete v době běhu, používá ji jen v kontextu JavaScriptu. A zatím je to všechno v pořádku.

class MyClass {}
let abc: MyClass; // ts recognizes as instance type
abc = new MyClass(); // completely fine, used here as the javascript value

Skutečný problém však nastává, když třídu z modulu dynamicky exportujete. Když třídu exportujete určitými způsoby, TypeScript může exportovat pouze hodnotu třídy v JavaScriptu a neexportuje typ. Takže pokud ji importujete do jiného modulu a pokusíte se na ni odkazovat jako na typ, dostanete chybu 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

Když se to stane, zejména pokud je to mimo vaši kontrolu, moje řešení, jak získat typ instance, bylo jednoduše použít InstanceType a typeof:

import {MyClass} from './myclass';

let abc: InstanceType<typeof MyClass>; // no error
// the rest...

Operátor typeof vám získá typ konstruktora třídy pro hodnotu třídy a generický typ InstanceType vám získá typ instance, který potřebujete.

Odpověď č. 4

Nejprve změňte typ souboru na .tsx

pak stiskněte F1 a napište "Reload Window"

:)

Odpověď č. 5

To mělo být komentářem, ale nemám dostatečnou reputaci. Chtěl jsem sdílet, že čistý způsob, jak použít řešení doporučené přijatou odpovědí, je deklarovat alias typu se stejným názvem (nezpůsobuje to konflikt). Pak můžete svůj typ používat stejným způsobem, jako byste normálně používali instance typu.

Doplnění k příkladu:

import {MyClass} from './myclass';

type MyClass = InstanceType<typeof MyClass>;

let abc: MyClass; // still no error!

Úprava: Zdá se, že typový import také funguje a vypadá to čistěji:

import type {MyClass} from './myclass';

Nevýhodou přístupu import type je, že jej nelze použít jako hodnotu (např. při vytváření new MyClass(...)).

Související články