Właściwość „wartość” nie istnieje w typie „Tylko do odczytu <{}>”

155

Muszę utworzyć formularz, który będzie wyświetlał coś na podstawie wartości zwracanej przez API. Pracuję z następującym kodem:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value); //error here
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} /> // error here
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Otrzymuję następujący błąd:

error TS2339: Property 'value' does not exist on type 'Readonly<{}>'.

Otrzymałem ten błąd w dwóch wierszach, które skomentowałem w kodzie. Ten kod nie jest nawet mój, mam go z oficjalnej strony React ( https://reactjs.org/docs/forms.html ), ale tutaj nie działa.

Używam narzędzia do tworzenia i reagowania.

Luis Henrique Zimmermann
źródło
Twój problem leży gdzie indziej - zobacz to demo
Ted
Wiem, że działa na wszystkich tych witrynach „kompilatorów”, ale doradzili mi, abym użył tego do wykonania projektu github.com/Microsoft/TypeScript-React-Starter , a przez kompilator TypeScript nie działa
Luis Henrique Zimmermann

Odpowiedzi:

264

Definicja Component jest następująca :

interface Component<P = {}, S = {}> extends ComponentLifecycle<P, S> { }

Co oznacza, że typ domyślny dla państwa (i rekwizytów) wynosi: {}.
Jeśli chcesz, aby twój komponent był valuew stanie, musisz go zdefiniować w następujący sposób:

class App extends React.Component<{}, { value: string }> {
    ...
}

Lub:

type MyProps = { ... };
type MyState = { value: string };
class App extends React.Component<MyProps, MyState> {
    ...
}
Nitzan Tomer
źródło
3
O mój Boże, koleś, teraz zadziałało, po prostu odpowiedz mi jeszcze na jedną rzecz, ta składnia jest związana z TypeScript, prawda? ponieważ w oficjalnej witrynie React nie ma nic podobnego
Luis Henrique Zimmermann
3
Tak, to jest ściśle związane z maszynopisem.
Nitzan Tomer
1
Właściwa definicja to: class Square rozszerza React.Component <{value: string}, {}> {...}
Rodrigo Perez Burgues
58

Oprócz odpowiedzi @ nitzan-tomer masz również możliwość korzystania z inferfaces :

interface MyProps {
  ...
}

interface MyState {
  value: string
}

class App extends React.Component<MyProps, MyState> {
  ...
}

// Or with hooks, something like

const App = ({}: MyProps) => {
  const [value, setValue] = useState<string>(null);
  ...
};

Albo jest w porządku, o ile jesteś konsekwentny.

Lew
źródło
1
Podsumuj proszę, co spójne oznacza w kontekście Twojego postu, aby można było mieć jego pełną wartość bez konieczności czytania artykułu z medium (co jest bardzo przydatnym linkiem, dziękuję).
Karl Richter
9

Problem polega na tym, że nie zadeklarowałeś swojego stanu interfejsu, zastąp go odpowiednim typem zmiennej „wartość”

Oto dobre odniesienie

interface AppProps {
   //code related to your props goes here
}

interface AppState {
   value: any
}

class App extends React.Component<AppProps, AppState> {
  // ...
}
Minuka ArTy Weerathunga
źródło
0

event.targetjest typu, EventTargetktóry nie zawsze ma wartość. Jeśli jest to element DOM, musisz rzucić go na odpowiedni typ:

handleChange(event) {
    this.setState({value: (event.target as HTMLInputElement).value});
}

Pozwoli to również wywnioskować „prawidłowy” typ zmiennej stanu, chociaż podanie jawności jest prawdopodobnie lepsze

apokryfos
źródło
Myślę, że otrzymuje błąd, gdy próbuje zainicjować ciąg w konstruktorze, a nie w programie obsługi zdarzeń
module