Using state in react with TypeScript

JavascriptReactjs

Javascript Problem Overview


I am new to TypeScript. I've got a problem with displaying this.state.something inside the render method or assigning it to a variable inside a function.

Have a look at the most important piece of code:

interface State {
    playOrPause?: string;
}

class Player extends React.Component {
    constructor() {
        super();

        this.state = {
            playOrPause: 'Play'
        };
    }

    render() {
        return(
            <div>
                <button
                    ref={playPause => this.playPause = playPause}
                    title={this.state.playOrPause} // in this line I get an error
                    >
                    Play
                </button>
           </div>
        );
    }
}

The errors says: "[ts] Property 'playOrPause' does not exist on type 'ReadOnly<{}>'.

I tried to declare the playOrPause property to be a type of string and it didn't work. What am I missing here to make it work?

Javascript Solutions


Solution 1 - Javascript

You need to declare that your component is using the State interface, it used by Typescript's Generics.

interface IProps {
}

interface IState {
  playOrPause?: string;
}

class Player extends React.Component<IProps, IState> {
  // ------------------------------------------^
  constructor(props: IProps) {
    super(props);

    this.state = {
      playOrPause: 'Play'
    };
  }

  render() {
    return(
      <div>
        <button
          ref={playPause => this.playPause = playPause}
          title={this.state.playOrPause} // in this line I get an error
        >
          Play
        </button>
      </div>
    );
  }
}

Solution 2 - Javascript

In case anyone is wondering how to implement it in functional components with hooks ( not in a class):

const [value, setValue] = useState<number>(0);

useState is a generic function, that means that it can accept a type parameter. This type-parameter will tell TypeScript which types are acceptable for this state.

Solution 3 - Javascript

In my case ( working with TypeScript, and the state value was actually a boolean ) I've had the same problem, I've fixed it by passing the state value I wanted to mark as output to String():

import React, { Component } from 'react';

interface ITestProps {
  name: string;
}

interface ITestState {
  toggle: boolean;
}

class Test extends Component<ITestProps, ITestState> {
  constructor(props: ITestProps) {
    super(props);

    this.state = {
      toggle: false,
    };

    this.onClick = this.onClick.bind(this);
  }

  onClick() {
    this.setState((previousState, props) => ({
      toggle: !previousState.toggle,
    }));
  }

  render() {
    return (
      <div>
        Hello, {this.props.name}!
        <br />
        Toggle state is: {String(this.state.toggle)}
      </div>
    )
  }
}

Solution 4 - Javascript

Just declare interface or type with property, types, and annotate it to state. the ? mean optional:

interface ITestProps {}

interface ITestState {
  playOrPause?: string;
}

class Player extends React.Component<ITestProps, ITestState> {

  state = {
     playOrPause: 'Play'
  };
  

  render() {
    return // your code here
}

You can add more value as per your need to interface above if then you need the same state to pass it to child component you just need to create a file with .d.ts and you should be good to go!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMaciej S.View Question on Stackoverflow
Solution 1 - JavascriptfelixmoshView Answer on Stackoverflow
Solution 2 - JavascriptPedroMiottiView Answer on Stackoverflow
Solution 3 - JavascriptDr4kk0nnysView Answer on Stackoverflow
Solution 4 - JavascriptEricgitView Answer on Stackoverflow